ValidateSuite checks a suite and gives all the problems that it finds.
Each problem has the path of its field. ValidateSuite does not save the
suite, so an editor can call it after each change.
ValidateSuite does the same checks as synq-recon check-config without
--db. It also does the checks that apply only to suites that run in
Coalesce Quality.
ValidateSuite does not connect to a warehouse. Thus it does not find a
query that refers to a table that does not exist. To find these
problems, use SuiteConfigService.CheckSuiteInWarehouse.
ValidateSuite does not compare the connection names with the integrations
of the workspace. A suite gets its integrations when it runs or when you
promote it.
A suite in the format that Coalesce Quality stores. The request does not
apply the validation rules of ReconciliationSuite. Thus an incorrect
suite gets to ValidateSuite, and the response has one issue for each
rule that the suite does not obey.
The suite from the yaml input. It is not set when the request gives the
suite as a proto, or when the YAML text does not give a suite.
Show child attributes
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Coalesce Quality Documentation","colors":{"primary":"#135594","light":"#e8f0f8","dark":"#0d3966"},"logo":{"light":"https://mintcdn.com/synq-15/VrNXC6Gv5xCECUGd/logo/coalesce-quality-logo.svg?fit=max\u0026auto=format\u0026n=VrNXC6Gv5xCECUGd\u0026q=85\u0026s=4ad60b616ed815902c710f413d59cf63","dark":"https://mintcdn.com/synq-15/VrNXC6Gv5xCECUGd/logo/coalesce-quality-logo-white.svg?fit=max\u0026auto=format\u0026n=VrNXC6Gv5xCECUGd\u0026q=85\u0026s=4d8c4a954595c0dfd25bfdf645e6cb56"},"favicon":{"light":"https://mintcdn.com/synq-15/xb0Db-MnOw_Ojah5/favicon.svg?fit=max\u0026auto=format\u0026n=xb0Db-MnOw_Ojah5\u0026q=85\u0026s=860c7081b896f01fe24af1c330da1796","dark":"https://mintcdn.com/synq-15/qs0RRq4z_2GWyKyp/favicon-dark.svg?fit=max\u0026auto=format\u0026n=qs0RRq4z_2GWyKyp\u0026q=85\u0026s=b740f42e7f6972f91d62be5b2840c805"},"navbar":{"links":[{"href":"https://coalesce.io/product/quality/","label":"Website"},{"href":"https://coalesce.io/product/request-demo/","label":"Book a Demo"}],"primary":{"type":"button","label":"Coalesce Quality Platform","href":"https://app.synq.io"}},"footer":{"socials":{"linkedin":"https://www.linkedin.com/company/coalesceio"}},"integrations":{"ga4":{"measurementId":"G-P55J2JTKF1"}},"styling":{"latex":false},"navigation":{"global":{"anchors":[{"anchor":"Blog","icon":"newspaper","href":"https://coalesce.io/resources/"},{"anchor":"Changelog","icon":"rocket","href":"https://synq.io/changelog"}]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"synq-15","hasAudioNarration":false,"actualSubdomain":"synq-15","customDomains":["docs.synq.io"],"gitSource":{"type":"github","owner":"getsynq","repo":"docs","deployBranch":"master","contentDirectory":"","isPrivate":false,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ae4bce77e124eba0d7b8466","collectionId":"b27469a1-8245-4341-8e48-3bd0c2081fd7","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ae4bce77e124eba0d7b8466"},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6ae66a13039e90b0fea0fef8","clientVersion":"0.0.4044","searchFilterCounts":[{"language":"default","tag":"Documentation","count":448},{"language":"default","tag":"Developer API","count":342},{"language":"default","tag":"REST API","count":331},{"language":"default","tag":"synq.incidents.v1.IncidentsService","count":14},{"language":"default","tag":"Reconciliations","count":13},{"language":"default","tag":"synq.alerts.services.v2.AlertsService","count":13},{"language":"default","tag":"synq.monitors.automated_monitors.v1.DeploymentRulesService","count":12},{"language":"default","tag":"Monitors","count":11},{"language":"default","tag":"synq.domains.v2.DomainsService","count":10},{"language":"default","tag":"synq.users.v1.UsersService","count":10}]},"assistantConfig":{},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"global.css","content":".dark img[src^=\"/images/\"]{background:#fff;border-radius:.5rem;padding:4px}"}],"page":{"pagePath":"api-reference/synqagentreconv1yamlservice/validatesuite","slug":"/api-reference/synqagentreconv1yamlservice/validatesuite","pageMetadata":{"title":"ValidateSuite","description":"ValidateSuite checks a suite and gives all the problems that it finds.\n Each problem has the path of its field. ValidateSuite does not save the\n suite, so an editor can call it after each change.\n\n ValidateSuite does the same checks as `synq-recon check-config` without\n `--db`. It also does the checks that apply only to suites that run in\n Coalesce Quality.\n\n ValidateSuite does not connect to a warehouse. Thus it does not find a\n query that refers to a table that does not exist. To find these\n problems, use SuiteConfigService.CheckSuiteInWarehouse.\n\n ValidateSuite does not compare the connection names with the integrations\n of the workspace. A suite gets its integrations when it runs or when you\n promote it.","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/agent/recon/v1/yaml/validate","href":"/api-reference/synqagentreconv1yamlservice/validatesuite","autogeneratedByOpenApi":true},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n code: \"code\",\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsx(_components.p, {\n children: \"ValidateSuite checks a suite and gives all the problems that it finds.\\nEach problem has the path of its field. ValidateSuite does not save the\\nsuite, so an editor can call it after each change.\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"ValidateSuite does the same checks as \", _jsx(_components.code, {\n children: \"synq-recon check-config\"\n }), \" without\\n\", _jsx(_components.code, {\n children: \"--db\"\n }), \". It also does the checks that apply only to suites that run in\\nCoalesce Quality.\"]\n }), \"\\n\", _jsx(_components.p, {\n children: \"ValidateSuite does not connect to a warehouse. Thus it does not find a\\nquery that refers to a table that does not exist. To find these\\nproblems, use SuiteConfigService.CheckSuiteInWarehouse.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"ValidateSuite does not compare the connection names with the integrations\\nof the workspace. A suite gets its integrations when it runs or when you\\npromote it.\"\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){return _jsx(_Fragment,{})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"ValidateSuite","description":"ValidateSuite checks a suite and gives all the problems that it finds.\n Each problem has the path of its field. ValidateSuite does not save the\n suite, so an editor can call it after each change.\n\n ValidateSuite does the same checks as `synq-recon check-config` without\n `--db`. It also does the checks that apply only to suites that run in\n Coalesce Quality.\n\n ValidateSuite does not connect to a warehouse. Thus it does not find a\n query that refers to a table that does not exist. To find these\n problems, use SuiteConfigService.CheckSuiteInWarehouse.\n\n ValidateSuite does not compare the connection names with the integrations\n of the workspace. A suite gets its integrations when it runs or when you\n promote it.","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/agent/recon/v1/yaml/validate","href":"/api-reference/synqagentreconv1yamlservice/validatesuite","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":["/_mintlify/custom/synq-15/7fe5b7dda612017d/region.js"],"openApiReferenceData":{"operation":{"tags":["synq.agent.recon.v1.YamlService"],"summary":"ValidateSuite","description":"ValidateSuite checks a suite and gives all the problems that it finds.\n Each problem has the path of its field. ValidateSuite does not save the\n suite, so an editor can call it after each change.\n\n ValidateSuite does the same checks as `synq-recon check-config` without\n `--db`. It also does the checks that apply only to suites that run in\n Coalesce Quality.\n\n ValidateSuite does not connect to a warehouse. Thus it does not find a\n query that refers to a table that does not exist. To find these\n problems, use SuiteConfigService.CheckSuiteInWarehouse.\n\n ValidateSuite does not compare the connection names with the integrations\n of the workspace. A suite gets its integrations when it runs or when you\n promote it.","operationId":"synq.agent.recon.v1.YamlService.ValidateSuite","requestBody":"0a4b557f-f6a8-4cdd-b656-6400dba0e35b","responses":{"200":"bfeb76a8-11aa-4d28-9e9e-e2ecf42b45e1"},"method":"post","type":"path","servers":["48744bfd-8999-4797-84b4-2998e5a947c5","75e3b0c9-c49c-4335-af67-cbc071a8c92d","619e14d1-f915-4478-a7e2-ad1b0ade05a7"],"security":["e6e3a4e7-a0de-460f-a4f0-9753c38136eb"],"path":"/api/agent/recon/v1/yaml/validate","baseUrlOptions":["https://developer.synq.io","https://api.us.synq.io","https://api.au.synq.io"],"title":"ValidateSuite","codeSamples":[],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{},"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","title":"suite","required":["suite"],"properties":{"suite":{"type":"object","properties":{"name":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9_-]*$","description":"Short machine identifier for the suite.\n Unique machine identifier for the suite, used as the stable key for tracking runs over time.\n Alphanumerics, hyphens, and underscores. May be a UUID.","isRequired":true,"uniqueKey":"oneOf.0.suite.name","typeLabel":"string"},"title":{"oneOf":[{"type":"string","description":"Human-readable title for the suite.\n Displayed in dashboards and reports. Defaults to name when not set.","uniqueKey":"oneOf.0.suite.title.oneOf.0","typeLabel":"string"},{"type":"null","description":"Human-readable title for the suite.\n Displayed in dashboards and reports. Defaults to name when not set.","uniqueKey":"oneOf.0.suite.title.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.title","typeLabel":"string | null"},"description":{"oneOf":[{"type":"string","description":"Optional longer description of the suite's purpose.","uniqueKey":"oneOf.0.suite.description.oneOf.0","typeLabel":"string"},{"type":"null","description":"Optional longer description of the suite's purpose.","uniqueKey":"oneOf.0.suite.description.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.description","typeLabel":"string | null"},"reconciliations":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9_-]*$","description":"Unique machine identifier within the suite. Alphanumerics, hyphens, and underscores. May be a UUID.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].name","typeLabel":"string"},"source":{"oneOf":[{"type":"object","title":"Dataset","description":"Source dataset to compare from — the \"expected\" or \"authoritative\" side.","required":["connection","query"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.0.connection","typeLabel":"string"},"query":{"type":"string","title":"query","description":"Raw SQL query returning the dataset.\n Should be a SELECT or WITH (CTE) statement.\n Supports template variable interpolation via {{variable_name}} syntax.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.0.query","typeLabel":"string"},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.0.asOf.oneOf.0","typeLabel":"string"},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.0.asOf.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.0.asOf","typeLabel":"string | null"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.0.columns.items.[INDEX]","typeLabel":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.0.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.0.excludeColumns.items.[INDEX]","typeLabel":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.0.excludeColumns","typeLabel":"string[]"}},"additionalProperties":false,"isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.0","typeLabel":"Dataset · object"},{"type":"object","title":"Dataset","description":"Source dataset to compare from — the \"expected\" or \"authoritative\" side.","required":["connection","table"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.connection","typeLabel":"string"},"table":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Table or view name (e.g., \"orders\", \"fact_sales\").\n Required — this is the actual object name.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.name","typeLabel":"string"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.columns.items.[INDEX]","typeLabel":"string"},"description":"Explicit list of columns to include in the comparison.\n When set, only these columns are selected from the table.\n Mutually exclusive with exclude_columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.excludeColumns.items.[INDEX]","typeLabel":"string"},"description":"Columns to exclude from the comparison.\n All columns except these are selected (resolved at runtime via table metadata).\n Useful for skipping volatile columns (e.g., updated_at, etl_batch_id).\n Mutually exclusive with columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.excludeColumns","typeLabel":"string[]"},"database":{"oneOf":[{"type":"string","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.database.oneOf.0","typeLabel":"string"},{"type":"null","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.database.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.database","typeLabel":"string | null"},"schema":{"oneOf":[{"type":"string","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.schema.oneOf.0","typeLabel":"string"},{"type":"null","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.schema.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.schema","typeLabel":"string | null"},"where":{"oneOf":[{"type":"string","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\"","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\"","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.where.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table.where","typeLabel":"string | null"}},"title":"table","required":["name"],"additionalProperties":false,"description":"Table reference with optional column selection.\n Automatically generates a SELECT query from the table metadata.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.table","typeLabel":"table · object"},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.asOf.oneOf.0","typeLabel":"string"},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.asOf.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.asOf","typeLabel":"string | null"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.columns.items.[INDEX]","typeLabel":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.excludeColumns.items.[INDEX]","typeLabel":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1.excludeColumns","typeLabel":"string[]"}},"additionalProperties":false,"isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source.oneOf.1","typeLabel":"Dataset · object"}],"isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].source","typeLabel":"Dataset · object"},"target":{"oneOf":[{"type":"object","title":"Dataset","description":"Target dataset to compare against — the \"actual\" or \"replicated\" side.","required":["connection","query"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.0.connection","typeLabel":"string"},"query":{"type":"string","title":"query","description":"Raw SQL query returning the dataset.\n Should be a SELECT or WITH (CTE) statement.\n Supports template variable interpolation via {{variable_name}} syntax.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.0.query","typeLabel":"string"},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.0.asOf.oneOf.0","typeLabel":"string"},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.0.asOf.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.0.asOf","typeLabel":"string | null"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.0.columns.items.[INDEX]","typeLabel":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.0.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.0.excludeColumns.items.[INDEX]","typeLabel":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.0.excludeColumns","typeLabel":"string[]"}},"additionalProperties":false,"isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.0","typeLabel":"Dataset · object"},{"type":"object","title":"Dataset","description":"Target dataset to compare against — the \"actual\" or \"replicated\" side.","required":["connection","table"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.connection","typeLabel":"string"},"table":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Table or view name (e.g., \"orders\", \"fact_sales\").\n Required — this is the actual object name.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.name","typeLabel":"string"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.columns.items.[INDEX]","typeLabel":"string"},"description":"Explicit list of columns to include in the comparison.\n When set, only these columns are selected from the table.\n Mutually exclusive with exclude_columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.excludeColumns.items.[INDEX]","typeLabel":"string"},"description":"Columns to exclude from the comparison.\n All columns except these are selected (resolved at runtime via table metadata).\n Useful for skipping volatile columns (e.g., updated_at, etl_batch_id).\n Mutually exclusive with columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.excludeColumns","typeLabel":"string[]"},"database":{"oneOf":[{"type":"string","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.database.oneOf.0","typeLabel":"string"},{"type":"null","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.database.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.database","typeLabel":"string | null"},"schema":{"oneOf":[{"type":"string","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.schema.oneOf.0","typeLabel":"string"},{"type":"null","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.schema.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.schema","typeLabel":"string | null"},"where":{"oneOf":[{"type":"string","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\"","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\"","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.where.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table.where","typeLabel":"string | null"}},"title":"table","required":["name"],"additionalProperties":false,"description":"Table reference with optional column selection.\n Automatically generates a SELECT query from the table metadata.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.table","typeLabel":"table · object"},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.asOf.oneOf.0","typeLabel":"string"},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.asOf.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.asOf","typeLabel":"string | null"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.columns.items.[INDEX]","typeLabel":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.excludeColumns.items.[INDEX]","typeLabel":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1.excludeColumns","typeLabel":"string[]"}},"additionalProperties":false,"isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target.oneOf.1","typeLabel":"Dataset · object"}],"isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].target","typeLabel":"Dataset · object"},"title":{"oneOf":[{"type":"string","description":"Human-readable title. Displayed in reports. Defaults to name when not set.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].title.oneOf.0","typeLabel":"string"},{"type":"null","description":"Human-readable title. Displayed in reports. Defaults to name when not set.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].title.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].title","typeLabel":"string | null"},"description":{"oneOf":[{"type":"string","description":"Optional longer description explaining what this reconciliation validates.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].description.oneOf.0","typeLabel":"string"},{"type":"null","description":"Optional longer description explaining what this reconciliation validates.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].description.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].description","typeLabel":"string | null"},"keyColumn":{"oneOf":[{"type":"string","description":"Deprecated: use key_columns instead. Single primary key column used for\n ordering and segmentation during bisection. Retained for backward\n compatibility — existing single-key configs and stored audit logs keep\n working. When key_columns is set, this field is ignored. Readers should\n resolve the effective key via key_columns first, falling back to this.","deprecated":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].keyColumn.oneOf.0","typeLabel":"string"},{"type":"null","description":"Deprecated: use key_columns instead. Single primary key column used for\n ordering and segmentation during bisection. Retained for backward\n compatibility — existing single-key configs and stored audit logs keep\n working. When key_columns is set, this field is ignored. Readers should\n resolve the effective key via key_columns first, falling back to this.","deprecated":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].keyColumn.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].keyColumn","typeLabel":"string | null"},"keyColumns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].keyColumns.items.[INDEX]","typeLabel":"string"},"description":"Ordered list of key columns used for ordering and segmentation during\n bisection. Supports composite (multi-column) keys; the bisection orders and\n range-filters on the column tuple so the engine can prune via a matching\n primary key / index. A single-element list is equivalent to setting\n key_column. Required for ROW_CHECKSUM and ROW_COUNT modes (this or the\n deprecated key_column). Optional in AGGREGATE mode, where it only stands in\n for group_columns when those are unset.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].keyColumns","typeLabel":"string[]"},"mode":{"type":"string","title":"ReconciliationMode","enum":["RECONCILIATION_MODE_UNSPECIFIED","RECONCILIATION_MODE_ROW_COUNT","RECONCILIATION_MODE_ROW_CHECKSUM","RECONCILIATION_MODE_AGGREGATE"],"description":"Comparison mode controlling how source and target are compared.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].mode","typeLabel":"enum\u003cstring>"},"hashAlgorithm":{"oneOf":[{"type":"string","title":"HashAlgorithm","enum":["HASH_ALGORITHM_UNSPECIFIED","HASH_ALGORITHM_MD5","HASH_ALGORITHM_FARM_FINGERPRINT","HASH_ALGORITHM_XXHASH64"],"description":"Hash algorithm for row checksums in ROW_CHECKSUM mode.\n When unset, auto-negotiates the best common algorithm between the\n source and target database dialects.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].hashAlgorithm.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"HashAlgorithm","enum":["HASH_ALGORITHM_UNSPECIFIED","HASH_ALGORITHM_MD5","HASH_ALGORITHM_FARM_FINGERPRINT","HASH_ALGORITHM_XXHASH64"],"description":"Hash algorithm for row checksums in ROW_CHECKSUM mode.\n When unset, auto-negotiates the best common algorithm between the\n source and target database dialects.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].hashAlgorithm.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].hashAlgorithm","typeLabel":"enum\u003cstring> | null"},"columnMapping":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string","minLength":1,"description":"Column name in the source dataset.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].columnMapping.items.[INDEX].source","typeLabel":"string"},"target":{"type":"string","minLength":1,"description":"Corresponding column name in the target dataset.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].columnMapping.items.[INDEX].target","typeLabel":"string"}},"title":"ColumnMapping","required":["source","target"],"additionalProperties":false,"description":"ColumnMapping maps a source column name to a target column name.\n Used when source and target use different naming conventions for the same data\n (e.g., snake_case vs SCREAMING_SNAKE_CASE, or completely different names).\n Only columns with different names need explicit mapping — columns with\n identical names (or case-insensitive matches when case_insensitive is true)\n are matched automatically.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].columnMapping.items.[INDEX]","typeLabel":"ColumnMapping · object"},"description":"Explicit column name mapping between source and target.\n Only columns with different names need mapping — identical names\n (or case-insensitive matches) are matched automatically.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].columnMapping","typeLabel":"ColumnMapping · object[]"},"caseInsensitive":{"oneOf":[{"type":"boolean","description":"When true, automatically matches columns differing only in letter case\n (e.g., user_id matches USER_ID). Defaults to true when not set.\n Set to false to require exact case matching.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].caseInsensitive.oneOf.0","typeLabel":"boolean"},{"type":"null","description":"When true, automatically matches columns differing only in letter case\n (e.g., user_id matches USER_ID). Defaults to true when not set.\n Set to false to require exact case matching.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].caseInsensitive.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].caseInsensitive","typeLabel":"boolean | null"},"bisection":{"oneOf":[{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether bisection drill-down is enabled.\n When false, only the quick-check (count + checksum) runs — mismatches\n are detected but not localized to specific rows.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.enabled","typeLabel":"boolean"},"factor":{"oneOf":[{"type":"integer","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.factor.oneOf.0","typeLabel":"integer\u003cint32>"},{"type":"null","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.factor.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.factor","typeLabel":"integer\u003cint32> | null"},"threshold":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.threshold.oneOf.0","typeLabel":"integer\u003cint32>"},{"type":"null","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.threshold.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.threshold","typeLabel":"integer\u003cint32> | null"},"strategy":{"type":"string","title":"SegmentationStrategy","enum":["SEGMENTATION_STRATEGY_UNSPECIFIED","SEGMENTATION_STRATEGY_QUANTILE","SEGMENTATION_STRATEGY_HASH","SEGMENTATION_STRATEGY_TIME"],"description":"Segmentation strategy for splitting key ranges.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.strategy","typeLabel":"enum\u003cstring>"},"timeColumn":{"oneOf":[{"type":"string","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.timeColumn.oneOf.0","typeLabel":"string"},{"type":"null","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.timeColumn.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.timeColumn","typeLabel":"string | null"},"timeGranularity":{"type":"string","title":"TimeGranularity","enum":["TIME_GRANULARITY_UNSPECIFIED","TIME_GRANULARITY_HOUR","TIME_GRANULARITY_DAY","TIME_GRANULARITY_WEEK","TIME_GRANULARITY_MONTH","TIME_GRANULARITY_QUARTER","TIME_GRANULARITY_YEAR"],"description":"Granularity for time-based segmentation. Default: DAY.\n Controls the width of each time bucket when strategy is TIME.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0.timeGranularity","typeLabel":"enum\u003cstring>"}},"title":"BisectionConfig","additionalProperties":false,"description":"Bisection drill-down configuration for ROW_CHECKSUM mode.\n Controls how the key range is recursively split to locate mismatches.\n When not set, uses sensible defaults (factor=32, threshold=16384).","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.0","typeLabel":"BisectionConfig · object"},{"type":"null","properties":{"enabled":{"type":"boolean","description":"Whether bisection drill-down is enabled.\n When false, only the quick-check (count + checksum) runs — mismatches\n are detected but not localized to specific rows."},"factor":{"oneOf":[{"type":"integer","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64."},{"type":"null","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64."}]},"threshold":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows."},{"type":"null","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows."}]},"strategy":{"type":"string","title":"SegmentationStrategy","enum":["SEGMENTATION_STRATEGY_UNSPECIFIED","SEGMENTATION_STRATEGY_QUANTILE","SEGMENTATION_STRATEGY_HASH","SEGMENTATION_STRATEGY_TIME"],"description":"Segmentation strategy for splitting key ranges."},"timeColumn":{"oneOf":[{"type":"string","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset."},{"type":"null","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset."}]},"timeGranularity":{"type":"string","title":"TimeGranularity","enum":["TIME_GRANULARITY_UNSPECIFIED","TIME_GRANULARITY_HOUR","TIME_GRANULARITY_DAY","TIME_GRANULARITY_WEEK","TIME_GRANULARITY_MONTH","TIME_GRANULARITY_QUARTER","TIME_GRANULARITY_YEAR"],"description":"Granularity for time-based segmentation. Default: DAY.\n Controls the width of each time bucket when strategy is TIME."}},"title":"BisectionConfig","additionalProperties":false,"description":"Bisection drill-down configuration for ROW_CHECKSUM mode.\n Controls how the key range is recursively split to locate mismatches.\n When not set, uses sensible defaults (factor=32, threshold=16384).","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].bisection","typeLabel":"BisectionConfig · object | null"},"reporting":{"oneOf":[{"type":"object","properties":{"level":{"type":"string","title":"MismatchDetailLevel","enum":["MISMATCH_DETAIL_LEVEL_UNSPECIFIED","MISMATCH_DETAIL_LEVEL_COUNT_ONLY","MISMATCH_DETAIL_LEVEL_WITH_KEYS","MISMATCH_DETAIL_LEVEL_DETAILED"],"description":"Output detail level for mismatched rows.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].reporting.oneOf.0.level","typeLabel":"enum\u003cstring>"},"sampleLimit":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].reporting.oneOf.0.sampleLimit.oneOf.0","typeLabel":"integer\u003cint32>"},{"type":"null","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].reporting.oneOf.0.sampleLimit.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].reporting.oneOf.0.sampleLimit","typeLabel":"integer\u003cint32> | null"},"consentAcknowledged":{"type":"boolean","description":"Explicit acknowledgment that detailed row data may be included in the audit log.\n Required when level is DETAILED to prevent accidental exposure of sensitive data.\n The caller must set this to true to confirm they understand the privacy implications.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].reporting.oneOf.0.consentAcknowledged","typeLabel":"boolean"}},"title":"ReportingConfig","additionalProperties":false,"description":"Reporting output configuration controlling how much detail is included\n in the audit log for mismatched rows.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].reporting.oneOf.0","typeLabel":"ReportingConfig · object"},{"type":"null","properties":{"level":{"type":"string","title":"MismatchDetailLevel","enum":["MISMATCH_DETAIL_LEVEL_UNSPECIFIED","MISMATCH_DETAIL_LEVEL_COUNT_ONLY","MISMATCH_DETAIL_LEVEL_WITH_KEYS","MISMATCH_DETAIL_LEVEL_DETAILED"],"description":"Output detail level for mismatched rows."},"sampleLimit":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included."},{"type":"null","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included."}]},"consentAcknowledged":{"type":"boolean","description":"Explicit acknowledgment that detailed row data may be included in the audit log.\n Required when level is DETAILED to prevent accidental exposure of sensitive data.\n The caller must set this to true to confirm they understand the privacy implications."}},"title":"ReportingConfig","additionalProperties":false,"description":"Reporting output configuration controlling how much detail is included\n in the audit log for mismatched rows.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].reporting.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].reporting","typeLabel":"ReportingConfig · object | null"},"aggregate":{"oneOf":[{"type":"object","properties":{"measures":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name to aggregate. Must exist in both source and target datasets\n (after column mapping is applied).","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.measures.items.[INDEX].column","typeLabel":"string"},"functions":{"type":"array","items":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"AggregateFunction defines the supported SQL aggregate functions\n for measure comparisons in aggregate reconciliation mode.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.measures.items.[INDEX].functions.items.[INDEX]","typeLabel":"enum\u003cstring>"},"minItems":1,"description":"Aggregate functions to apply to this column.\n Multiple functions produce multiple measure comparisons from one column.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.measures.items.[INDEX].functions","typeLabel":"enum\u003cstring>[]"}},"title":"Measure","required":["column"],"additionalProperties":false,"description":"Measure defines a column and aggregate function(s) to compare\n between source and target datasets.\n A single measure with multiple functions expands into multiple comparisons\n (e.g., column=\"amount\" functions=[SUM, AVG] produces \"SUM(amount)\" and \"AVG(amount)\").","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.measures.items.[INDEX]","typeLabel":"Measure · object"},"minItems":1,"description":"Measures to compare between source and target.\n Each measure defines a column and one or more aggregate functions to apply.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.measures","typeLabel":"Measure · object[]"},"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.absolute.oneOf.0","typeLabel":"number\u003cdouble>"},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.absolute.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.absolute","typeLabel":"number\u003cdouble> | null"},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.percentage.oneOf.0","typeLabel":"number\u003cdouble>"},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.percentage.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.percentage","typeLabel":"number\u003cdouble> | null"},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.percentageBasis","typeLabel":"enum\u003cstring>"},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX].column","typeLabel":"string"},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX].thresholds","typeLabel":"any"}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX]","typeLabel":"ColumnThresholdOverride · object"},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perColumn","typeLabel":"ColumnThresholdOverride · object[]"},"perMeasure":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\").","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].column","typeLabel":"string"},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].thresholds","typeLabel":"any"},"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].function","typeLabel":"enum\u003cstring>"}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination).","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX]","typeLabel":"MeasureThresholdOverride · object"},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perMeasure","typeLabel":"MeasureThresholdOverride · object[]"}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0","typeLabel":"ThresholdConfig · object"},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds","typeLabel":"ThresholdConfig · object | null"},"groupColumns":{"type":"array","items":{"type":"string","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.groupColumns.items.[INDEX]","typeLabel":"string"},"description":"Columns defining the drill-down hierarchy for aggregate comparison.\n Falls back to the key columns if not set. With no key columns either, the\n whole dataset is compared as a single group, with no GROUP BY.\n\n Single column: flat GROUP BY comparison.\n group_columns: [\"region\"]\n → GROUP BY region\n\n Multiple columns: cumulative GROUP BY drill-down, pruning matched groups\n at each level to focus on divergent branches.\n group_columns: [\"region\", \"city\", \"store\"]\n → Level 0: GROUP BY region\n → Level 1: GROUP BY region, city (only for mismatched regions)\n → Level 2: GROUP BY region, city, store (only for mismatched cities)","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0.groupColumns","typeLabel":"string[]"}},"title":"AggregateConfig","additionalProperties":false,"description":"Aggregate comparison settings. Required when mode is AGGREGATE.\n Defines which measures to compare and tolerance thresholds.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.0","typeLabel":"AggregateConfig · object"},{"type":"null","properties":{"measures":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name to aggregate. Must exist in both source and target datasets\n (after column mapping is applied)."},"functions":{"type":"array","items":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"AggregateFunction defines the supported SQL aggregate functions\n for measure comparisons in aggregate reconciliation mode."},"minItems":1,"description":"Aggregate functions to apply to this column.\n Multiple functions produce multiple measure comparisons from one column."}},"title":"Measure","required":["column"],"additionalProperties":false,"description":"Measure defines a column and aggregate function(s) to compare\n between source and target datasets.\n A single measure with multiple functions expands into multiple comparisons\n (e.g., column=\"amount\" functions=[SUM, AVG] produces \"SUM(amount)\" and \"AVG(amount)\")."},"minItems":1,"description":"Measures to compare between source and target.\n Each measure defines a column and one or more aggregate functions to apply."},"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures."},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures."}]},"groupColumns":{"type":"array","items":{"type":"string"},"description":"Columns defining the drill-down hierarchy for aggregate comparison.\n Falls back to the key columns if not set. With no key columns either, the\n whole dataset is compared as a single group, with no GROUP BY.\n\n Single column: flat GROUP BY comparison.\n group_columns: [\"region\"]\n → GROUP BY region\n\n Multiple columns: cumulative GROUP BY drill-down, pruning matched groups\n at each level to focus on divergent branches.\n group_columns: [\"region\", \"city\", \"store\"]\n → Level 0: GROUP BY region\n → Level 1: GROUP BY region, city (only for mismatched regions)\n → Level 2: GROUP BY region, city, store (only for mismatched cities)"}},"title":"AggregateConfig","additionalProperties":false,"description":"Aggregate comparison settings. Required when mode is AGGREGATE.\n Defines which measures to compare and tolerance thresholds.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].aggregate","typeLabel":"AggregateConfig · object | null"},"errorHandling":{"oneOf":[{"type":"object","properties":{"queryTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.queryTimeout.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.queryTimeout.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.queryTimeout","typeLabel":"string\u003cduration> | null"},"maxRetries":{"oneOf":[{"type":"integer","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.maxRetries.oneOf.0","typeLabel":"integer\u003cint32>"},{"type":"null","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.maxRetries.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.maxRetries","typeLabel":"integer\u003cint32> | null"},"retryInitialDelay":{"oneOf":[{"type":"string","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryInitialDelay.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryInitialDelay.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryInitialDelay","typeLabel":"string\u003cduration> | null"},"retryBackoffFactor":{"oneOf":[{"type":"number","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryBackoffFactor.oneOf.0","typeLabel":"number\u003cdouble>"},{"type":"null","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryBackoffFactor.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryBackoffFactor","typeLabel":"number\u003cdouble> | null"}},"title":"ErrorHandlingConfig","additionalProperties":false,"description":"Error handling and retry configuration for database queries.\n Controls timeouts and retry behavior for transient failures.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.0","typeLabel":"ErrorHandlingConfig · object"},{"type":"null","properties":{"queryTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit."},{"type":"null","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit."}]},"maxRetries":{"oneOf":[{"type":"integer","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2."},{"type":"null","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2."}]},"retryInitialDelay":{"oneOf":[{"type":"string","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s."},{"type":"null","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s."}]},"retryBackoffFactor":{"oneOf":[{"type":"number","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0."},{"type":"null","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0."}]}},"title":"ErrorHandlingConfig","additionalProperties":false,"description":"Error handling and retry configuration for database queries.\n Controls timeouts and retry behavior for transient failures.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].errorHandling","typeLabel":"ErrorHandlingConfig · object | null"},"window":{"oneOf":[{"type":"object","properties":{"lookback":{"type":"string","format":"duration","description":"How far back to look from the current time.\n Defines the window as [now - lookback, now].\n Examples: \"336h\" (14 days), \"2h\", \"720h\" (30 days).","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].window.oneOf.0.lookback","typeLabel":"string\u003cduration>"},"column":{"oneOf":[{"type":"string","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].window.oneOf.0.column.oneOf.0","typeLabel":"string"},{"type":"null","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].window.oneOf.0.column.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].window.oneOf.0.column","typeLabel":"string | null"},"strategy":{"type":"string","title":"WindowStrategy","enum":["WINDOW_STRATEGY_UNSPECIFIED","WINDOW_STRATEGY_SLIDING","WINDOW_STRATEGY_FIXED"],"description":"Windowing strategy controlling how boundaries are computed.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].window.oneOf.0.strategy","typeLabel":"enum\u003cstring>"}},"title":"WindowConfig","required":["lookback"],"additionalProperties":false,"description":"Time window for incremental comparison.\n When set, automatically provides a {{window_start}} template variable\n for filtering queries to a recent time range.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].window.oneOf.0","typeLabel":"WindowConfig · object"},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause."},{"type":"null","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause."}]},"lookback":{"type":"string","format":"duration","description":"How far back to look from the current time.\n Defines the window as [now - lookback, now].\n Examples: \"336h\" (14 days), \"2h\", \"720h\" (30 days)."},"strategy":{"type":"string","title":"WindowStrategy","enum":["WINDOW_STRATEGY_UNSPECIFIED","WINDOW_STRATEGY_SLIDING","WINDOW_STRATEGY_FIXED"],"description":"Windowing strategy controlling how boundaries are computed."}},"title":"WindowConfig","required":["lookback"],"additionalProperties":false,"description":"Time window for incremental comparison.\n When set, automatically provides a {{window_start}} template variable\n for filtering queries to a recent time range.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].window.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].window","typeLabel":"WindowConfig · object | null"},"setup":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].setup.items.[INDEX].connection","typeLabel":"string"},"queries":{"type":"array","items":{"type":"string","minItems":1,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].setup.items.[INDEX].queries.items.[INDEX]","typeLabel":"string"},"minItems":1,"description":"SQL queries to execute in order on this connection.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].setup.items.[INDEX].queries","typeLabel":"string[]"}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].setup.items.[INDEX]","typeLabel":"ConnectionQueries · object"},"description":"Setup queries run before this specific reconciliation.\n Executes after suite-level setup but before data comparison.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].setup","typeLabel":"ConnectionQueries · object[]"},"teardown":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].teardown.items.[INDEX].connection","typeLabel":"string"},"queries":{"type":"array","items":{"type":"string","minItems":1,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].teardown.items.[INDEX].queries.items.[INDEX]","typeLabel":"string"},"minItems":1,"description":"SQL queries to execute in order on this connection.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].teardown.items.[INDEX].queries","typeLabel":"string[]"}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].teardown.items.[INDEX]","typeLabel":"ConnectionQueries · object"},"description":"Teardown queries run after this specific reconciliation completes.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].teardown","typeLabel":"ConnectionQueries · object[]"},"teardownOnFailure":{"oneOf":[{"type":"boolean","description":"Whether teardown runs on failure for this reconciliation.\n When not set, inherits from suite-level teardown_on_failure.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].teardownOnFailure.oneOf.0","typeLabel":"boolean"},{"type":"null","description":"Whether teardown runs on failure for this reconciliation.\n When not set, inherits from suite-level teardown_on_failure.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].teardownOnFailure.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].teardownOnFailure","typeLabel":"boolean | null"},"ignoreSetupErrors":{"oneOf":[{"type":"boolean","description":"When true, logs setup errors as warnings and continues.\n When not set, inherits from suite-level ignore_setup_errors.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].ignoreSetupErrors.oneOf.0","typeLabel":"boolean"},{"type":"null","description":"When true, logs setup errors as warnings and continues.\n When not set, inherits from suite-level ignore_setup_errors.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].ignoreSetupErrors.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].ignoreSetupErrors","typeLabel":"boolean | null"},"cutoff":{"oneOf":[{"type":"object","properties":{"source":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0.column","typeLabel":"string"},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0.aggregate","typeLabel":"enum\u003cstring>"},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0.query.oneOf.0","typeLabel":"string"},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0.query.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0.query","typeLabel":"string | null"}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0","typeLabel":"CutoffSideConfig · object"},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.source","typeLabel":"CutoffSideConfig · object | null"},"target":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0.column","typeLabel":"string"},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0.aggregate","typeLabel":"enum\u003cstring>"},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0.query.oneOf.0","typeLabel":"string"},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0.query.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0.query","typeLabel":"string | null"}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0","typeLabel":"CutoffSideConfig · object"},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.target","typeLabel":"CutoffSideConfig · object | null"},"combine":{"type":"string","title":"CutoffCombineStrategy","enum":["CUTOFF_COMBINE_STRATEGY_UNSPECIFIED","CUTOFF_COMBINE_STRATEGY_MIN","CUTOFF_COMBINE_STRATEGY_MAX","CUTOFF_COMBINE_STRATEGY_SOURCE","CUTOFF_COMBINE_STRATEGY_TARGET"],"description":"How to combine watermarks when both sides are configured.\n Default: MIN (use the smaller watermark for safety).\n Ignored when only one side has a watermark.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.combine","typeLabel":"enum\u003cstring>"},"truncate":{"type":"string","title":"CutoffTruncateUnit","enum":["CUTOFF_TRUNCATE_UNIT_UNSPECIFIED","CUTOFF_TRUNCATE_UNIT_HOUR","CUTOFF_TRUNCATE_UNIT_DAY","CUTOFF_TRUNCATE_UNIT_WEEK","CUTOFF_TRUNCATE_UNIT_MONTH","CUTOFF_TRUNCATE_UNIT_QUARTER","CUTOFF_TRUNCATE_UNIT_YEAR"],"description":"Truncate the combined watermark to a time boundary.\n Example: HOUR truncates 08:47:12 to 08:00:00.\n Applied after combining, before offset.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.truncate","typeLabel":"enum\u003cstring>"},"offset":{"oneOf":[{"type":"string","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.offset.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.offset.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.offset","typeLabel":"string\u003cduration> | null"},"applySource":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.column.oneOf.0","typeLabel":"string"},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.column.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.column","typeLabel":"string | null"},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\".","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.operator.oneOf.0","typeLabel":"string"},{"type":"null","description":"Comparison operator. Default: \"\u003c=\".","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.operator.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.operator","typeLabel":"string | null"}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0","typeLabel":"CutoffApplyConfig · object"},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource","typeLabel":"CutoffApplyConfig · object | null"},"applyTarget":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.column.oneOf.0","typeLabel":"string"},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.column.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.column","typeLabel":"string | null"},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\".","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.operator.oneOf.0","typeLabel":"string"},{"type":"null","description":"Comparison operator. Default: \"\u003c=\".","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.operator.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.operator","typeLabel":"string | null"}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0","typeLabel":"CutoffApplyConfig · object"},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget","typeLabel":"CutoffApplyConfig · object | null"}},"title":"CutoffConfig","additionalProperties":false,"description":"Dynamic cutoff filter for sync reconciliation.\n Derives a watermark from actual data to exclude rows not yet synced.\n Applied as WHERE filter to both source and target queries at runtime.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.0","typeLabel":"CutoffConfig · object"},{"type":"null","properties":{"source":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only."},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only."}]},"target":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only."},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only."}]},"combine":{"type":"string","title":"CutoffCombineStrategy","enum":["CUTOFF_COMBINE_STRATEGY_UNSPECIFIED","CUTOFF_COMBINE_STRATEGY_MIN","CUTOFF_COMBINE_STRATEGY_MAX","CUTOFF_COMBINE_STRATEGY_SOURCE","CUTOFF_COMBINE_STRATEGY_TARGET"],"description":"How to combine watermarks when both sides are configured.\n Default: MIN (use the smaller watermark for safety).\n Ignored when only one side has a watermark."},"truncate":{"type":"string","title":"CutoffTruncateUnit","enum":["CUTOFF_TRUNCATE_UNIT_UNSPECIFIED","CUTOFF_TRUNCATE_UNIT_HOUR","CUTOFF_TRUNCATE_UNIT_DAY","CUTOFF_TRUNCATE_UNIT_WEEK","CUTOFF_TRUNCATE_UNIT_MONTH","CUTOFF_TRUNCATE_UNIT_QUARTER","CUTOFF_TRUNCATE_UNIT_YEAR"],"description":"Truncate the combined watermark to a time boundary.\n Example: HOUR truncates 08:47:12 to 08:00:00.\n Applied after combining, before offset."},"offset":{"oneOf":[{"type":"string","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier."},{"type":"null","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier."}]},"applySource":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator."},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator."}]},"applyTarget":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator."},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator."}]}},"title":"CutoffConfig","additionalProperties":false,"description":"Dynamic cutoff filter for sync reconciliation.\n Derives a watermark from actual data to exclude rows not yet synced.\n Applied as WHERE filter to both source and target queries at runtime.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].cutoff","typeLabel":"CutoffConfig · object | null"},"annotations":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"minLength":1,"description":"String key for the annotation.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].annotations.items.[INDEX].name","typeLabel":"string"},"values":{"type":"array","items":{"type":"string","maxLength":100,"minLength":1,"maxItems":20,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].annotations.items.[INDEX].values.items.[INDEX]","typeLabel":"string"},"maxItems":20,"description":"Optional list of values that the annotation can carry.\n\n A value is something entities are filtered and searched by, not free-form\n metadata, so keep it to a label a person would pick out of a list. The limit\n is set to hold an identifier or a link the annotated system generated —\n truncating one of those produces a value that no longer resolves, and no\n longer matches the filter it exists for. Put prose in the entity\n description instead.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].annotations.items.[INDEX].values","typeLabel":"string[]"}},"title":"Annotation","required":["name"],"additionalProperties":false,"description":"Annotations can be used to annotate any entity with a key:value pair.\n These annotations can be used for filtering and searching entities.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].annotations.items.[INDEX]","typeLabel":"Annotation · object"},"description":"Case-level annotations. Merged with suite-level annotations and\n deployment-level annotations at promote time, then exposed on the\n case asset (PromotedReconCaseMetadata).","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].annotations","typeLabel":"Annotation · object[]"},"timeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for this reconciliation: its setup, quick check\n and any drill. Overrides the suite's execution.reconciliation_timeout.\n A reconciliation that exceeds it is recorded as failed with a timeout\n error and the run moves on to the next one. It never extends the run's\n own timeout. For a bound on each individual query, use\n error_handling.query_timeout.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].timeout.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Maximum wall-clock time for this reconciliation: its setup, quick check\n and any drill. Overrides the suite's execution.reconciliation_timeout.\n A reconciliation that exceeds it is recorded as failed with a timeout\n error and the run moves on to the next one. It never extends the run's\n own timeout. For a bound on each individual query, use\n error_handling.query_timeout.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].timeout.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].timeout","typeLabel":"string\u003cduration> | null"},"rowCount":{"oneOf":[{"type":"object","properties":{"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.absolute.oneOf.0","typeLabel":"number\u003cdouble>"},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.absolute.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.absolute","typeLabel":"number\u003cdouble> | null"},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.percentage.oneOf.0","typeLabel":"number\u003cdouble>"},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.percentage.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.percentage","typeLabel":"number\u003cdouble> | null"},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.percentageBasis","typeLabel":"enum\u003cstring>"},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX].column","typeLabel":"string"},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX].thresholds","typeLabel":"any"}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX]","typeLabel":"ColumnThresholdOverride · object"},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perColumn","typeLabel":"ColumnThresholdOverride · object[]"},"perMeasure":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\").","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].column","typeLabel":"string"},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].thresholds","typeLabel":"any"},"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].function","typeLabel":"enum\u003cstring>"}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination).","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX]","typeLabel":"MeasureThresholdOverride · object"},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perMeasure","typeLabel":"MeasureThresholdOverride · object[]"}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0","typeLabel":"ThresholdConfig · object"},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds","typeLabel":"ThresholdConfig · object | null"}},"title":"RowCountConfig","additionalProperties":false,"description":"Row count comparison settings. Only used when mode is ROW_COUNT.\n Sets the tolerance a difference in row counts may stay within.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.0","typeLabel":"RowCountConfig · object"},{"type":"null","properties":{"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal."},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal."}]}},"title":"RowCountConfig","additionalProperties":false,"description":"Row count comparison settings. Only used when mode is ROW_COUNT.\n Sets the tolerance a difference in row counts may stay within.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].rowCount","typeLabel":"RowCountConfig · object | null"},"comparison":{"oneOf":[{"type":"object","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale.oneOf.0.exact","typeLabel":"boolean"}},"additionalProperties":false,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale.oneOf.0","typeLabel":"exact · object"},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale.oneOf.1.places","typeLabel":"integer\u003cint32>"}},"additionalProperties":false,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale.oneOf.1","typeLabel":"places · object"},{"type":"null","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale.oneOf.2","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale","typeLabel":"exact · object | places · object | null"},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].column","typeLabel":"string"},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.0.exact","typeLabel":"boolean"}},"additionalProperties":false,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.0","typeLabel":"exact · object"},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one.","isRequired":true,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.1.places","typeLabel":"integer\u003cint32>"}},"additionalProperties":false,"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.1","typeLabel":"places · object"},{"type":"null","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.2","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale","typeLabel":"exact · object | places · object | null"},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].timestampPrecision.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].timestampPrecision.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].timestampPrecision","typeLabel":"enum\u003cstring> | null"},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone","typeLabel":"string | null"},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].targetTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].targetTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].targetTimeZone","typeLabel":"string | null"}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX]","typeLabel":"ColumnComparison · object"},"description":"Settings for individual columns, overriding the settings above.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.columns","typeLabel":"ColumnComparison · object[]"},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.timestampPrecision.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.timestampPrecision.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.timestampPrecision","typeLabel":"enum\u003cstring> | null"},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.sourceTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.sourceTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.sourceTimeZone","typeLabel":"string | null"},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.targetTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.targetTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0.targetTimeZone","typeLabel":"string | null"}},"title":"ComparisonConfig","additionalProperties":false,"description":"How column values are compared in ROW_CHECKSUM mode. Overrides the suite's\n comparison settings. When not set, the suite's apply, and without those\n every column is compared at the precision its types on both sides allow.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.0","typeLabel":"ComparisonConfig · object"},{"type":"null","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair."},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."}]}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column."},"description":"Settings for individual columns, overriding the settings above."},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."}]}},"title":"ComparisonConfig","additionalProperties":false,"description":"How column values are compared in ROW_CHECKSUM mode. Overrides the suite's\n comparison settings. When not set, the suite's apply, and without those\n every column is compared at the precision its types on both sides allow.","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX].comparison","typeLabel":"ComparisonConfig · object | null"}},"title":"Reconciliation","required":["name","source","target"],"additionalProperties":false,"description":"Reconciliation defines a single reconciliation scenario comparing data\n between a source and target dataset. Each reconciliation runs independently\n and produces its own pass/mismatch/fail result.\naggregate_config_required // aggregate config is required when mode is AGGREGATE\nkey_column_and_key_columns_mutually_exclusive // set either key_column (single) or key_columns (composite), not both\nkey_column_required_for_non_aggregate // key_column or key_columns is required unless mode is AGGREGATE\n","uniqueKey":"oneOf.0.suite.reconciliations.items.[INDEX]","typeLabel":"Reconciliation · object"},"minItems":1,"description":"Reconciliation scenarios to execute.\n Each reconciliation compares data between a source and target dataset.","uniqueKey":"oneOf.0.suite.reconciliations","typeLabel":"Reconciliation · object[]"},"setup":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map.","isRequired":true,"uniqueKey":"oneOf.0.suite.setup.items.[INDEX].connection","typeLabel":"string"},"queries":{"type":"array","items":{"type":"string","minItems":1,"uniqueKey":"oneOf.0.suite.setup.items.[INDEX].queries.items.[INDEX]","typeLabel":"string"},"minItems":1,"description":"SQL queries to execute in order on this connection.","uniqueKey":"oneOf.0.suite.setup.items.[INDEX].queries","typeLabel":"string[]"}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level.","uniqueKey":"oneOf.0.suite.setup.items.[INDEX]","typeLabel":"ConnectionQueries · object"},"description":"Setup queries run once before all reconciliations begin.\n Use for creating temp tables, loading fixtures, or preparing the environment.\n Queries execute in order; all connections run sequentially.","uniqueKey":"oneOf.0.suite.setup","typeLabel":"ConnectionQueries · object[]"},"teardown":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map.","isRequired":true,"uniqueKey":"oneOf.0.suite.teardown.items.[INDEX].connection","typeLabel":"string"},"queries":{"type":"array","items":{"type":"string","minItems":1,"uniqueKey":"oneOf.0.suite.teardown.items.[INDEX].queries.items.[INDEX]","typeLabel":"string"},"minItems":1,"description":"SQL queries to execute in order on this connection.","uniqueKey":"oneOf.0.suite.teardown.items.[INDEX].queries","typeLabel":"string[]"}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level.","uniqueKey":"oneOf.0.suite.teardown.items.[INDEX]","typeLabel":"ConnectionQueries · object"},"description":"Teardown queries run once after all reconciliations complete.\n Use for cleaning up temp tables or restoring state.","uniqueKey":"oneOf.0.suite.teardown","typeLabel":"ConnectionQueries · object[]"},"teardownOnFailure":{"type":"boolean","description":"Whether teardown runs even when reconciliations fail with infrastructure errors.\n When false (default), teardown is skipped on failure to preserve state for debugging.","uniqueKey":"oneOf.0.suite.teardownOnFailure","typeLabel":"boolean"},"ignoreSetupErrors":{"type":"boolean","description":"When true, logs setup query errors as warnings and continues execution\n instead of aborting the run. Useful when setup creates IF NOT EXISTS objects.","uniqueKey":"oneOf.0.suite.ignoreSetupErrors","typeLabel":"boolean"},"variables":{"type":"object","additionalProperties":{"type":"string","title":"value","uniqueKey":"oneOf.0.suite.variables.additionalProperties","typeLabel":"string"},"description":"Template variables for query interpolation via {{variable_name}} syntax.\n Values can be literal strings or template expressions:\n - Literal: \"2026-01-01\"\n - Time expression: \"{{today - 30d}}\", \"{{now - 2h}}\"\n - Built-in: \"{{now}}\", \"{{today}}\", \"{{window_start}}\"\n Variables are resolved once at the start of the run and frozen.","uniqueKey":"oneOf.0.suite.variables","typeLabel":"object"},"strictTimeReferences":{"type":"boolean","description":"When true, time reference detection (e.g. NOW(), CURRENT_DATE, GETDATE()\n in queries) returns an error instead of a warning. Prevents non-deterministic\n queries that produce different results on each run.","uniqueKey":"oneOf.0.suite.strictTimeReferences","typeLabel":"boolean"},"annotations":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"minLength":1,"description":"String key for the annotation.","isRequired":true,"uniqueKey":"oneOf.0.suite.annotations.items.[INDEX].name","typeLabel":"string"},"values":{"type":"array","items":{"type":"string","maxLength":100,"minLength":1,"maxItems":20,"uniqueKey":"oneOf.0.suite.annotations.items.[INDEX].values.items.[INDEX]","typeLabel":"string"},"maxItems":20,"description":"Optional list of values that the annotation can carry.\n\n A value is something entities are filtered and searched by, not free-form\n metadata, so keep it to a label a person would pick out of a list. The limit\n is set to hold an identifier or a link the annotated system generated —\n truncating one of those produces a value that no longer resolves, and no\n longer matches the filter it exists for. Put prose in the entity\n description instead.","uniqueKey":"oneOf.0.suite.annotations.items.[INDEX].values","typeLabel":"string[]"}},"title":"Annotation","required":["name"],"additionalProperties":false,"description":"Annotations can be used to annotate any entity with a key:value pair.\n These annotations can be used for filtering and searching entities.","uniqueKey":"oneOf.0.suite.annotations.items.[INDEX]","typeLabel":"Annotation · object"},"description":"Suite-level annotations. Each annotation is a name with zero or more\n string values. Applied to the deployed suite asset and inherited by every\n reconciliation case under the suite. Merged with per-case annotations and\n deployment-level annotations at promote time — the final, deduplicated\n list is exposed on PromotedReconSuiteMetadata / PromotedReconCaseMetadata\n and surfaced to the rest of the SYNQ platform via EntityAnnotations.","uniqueKey":"oneOf.0.suite.annotations","typeLabel":"Annotation · object[]"},"execution":{"oneOf":[{"type":"object","properties":{"timeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"oneOf.0.suite.execution.oneOf.0.timeout.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"oneOf.0.suite.execution.oneOf.0.timeout.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.execution.oneOf.0.timeout","typeLabel":"string\u003cduration> | null"},"concurrency":{"oneOf":[{"type":"integer","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum.","uniqueKey":"oneOf.0.suite.execution.oneOf.0.concurrency.oneOf.0","typeLabel":"integer\u003cint32>"},{"type":"null","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum.","uniqueKey":"oneOf.0.suite.execution.oneOf.0.concurrency.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.execution.oneOf.0.concurrency","typeLabel":"integer\u003cint32> | null"},"reconciliationTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"oneOf.0.suite.execution.oneOf.0.reconciliationTimeout.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"oneOf.0.suite.execution.oneOf.0.reconciliationTimeout.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.execution.oneOf.0.reconciliationTimeout","typeLabel":"string\u003cduration> | null"}},"title":"ExecutionConfig","additionalProperties":false,"description":"How runs of this suite execute: the wall-clock budget of a run and how\n many reconciliations run at the same time. Read by every run of the\n suite, local or server-side; a run-level override (a CLI flag, the\n execution_timeout on a trigger or on a deployment) takes precedence.","uniqueKey":"oneOf.0.suite.execution.oneOf.0","typeLabel":"ExecutionConfig · object"},{"type":"null","properties":{"timeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"}]},"concurrency":{"oneOf":[{"type":"integer","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum."},{"type":"null","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum."}]},"reconciliationTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"}]}},"title":"ExecutionConfig","additionalProperties":false,"description":"How runs of this suite execute: the wall-clock budget of a run and how\n many reconciliations run at the same time. Read by every run of the\n suite, local or server-side; a run-level override (a CLI flag, the\n execution_timeout on a trigger or on a deployment) takes precedence.","uniqueKey":"oneOf.0.suite.execution.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.execution","typeLabel":"ExecutionConfig · object | null"},"comparison":{"oneOf":[{"type":"object","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true","isRequired":true,"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.numericScale.oneOf.0.exact","typeLabel":"boolean"}},"additionalProperties":false,"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.numericScale.oneOf.0","typeLabel":"exact · object"},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one.","isRequired":true,"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.numericScale.oneOf.1.places","typeLabel":"integer\u003cint32>"}},"additionalProperties":false,"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.numericScale.oneOf.1","typeLabel":"places · object"},{"type":"null","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.numericScale.oneOf.2","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.numericScale","typeLabel":"exact · object | places · object | null"},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair.","isRequired":true,"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].column","typeLabel":"string"},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true","isRequired":true,"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.0.exact","typeLabel":"boolean"}},"additionalProperties":false,"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.0","typeLabel":"exact · object"},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one.","isRequired":true,"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.1.places","typeLabel":"integer\u003cint32>"}},"additionalProperties":false,"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.1","typeLabel":"places · object"},{"type":"null","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.2","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].numericScale","typeLabel":"exact · object | places · object | null"},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].timestampPrecision.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].timestampPrecision.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].timestampPrecision","typeLabel":"enum\u003cstring> | null"},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone","typeLabel":"string | null"},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].targetTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].targetTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX].targetTimeZone","typeLabel":"string | null"}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns.items.[INDEX]","typeLabel":"ColumnComparison · object"},"description":"Settings for individual columns, overriding the settings above.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.columns","typeLabel":"ColumnComparison · object[]"},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.timestampPrecision.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]},"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.timestampPrecision.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.timestampPrecision","typeLabel":"enum\u003cstring> | null"},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.sourceTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.sourceTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.sourceTimeZone","typeLabel":"string | null"},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.targetTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0.targetTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.comparison.oneOf.0.targetTimeZone","typeLabel":"string | null"}},"title":"ComparisonConfig","additionalProperties":false,"description":"Default comparison settings for every reconciliation in the suite. A\n reconciliation's own comparison settings take precedence, field by field.","uniqueKey":"oneOf.0.suite.comparison.oneOf.0","typeLabel":"ComparisonConfig · object"},{"type":"null","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair."},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."}]}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column."},"description":"Settings for individual columns, overriding the settings above."},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."}]}},"title":"ComparisonConfig","additionalProperties":false,"description":"Default comparison settings for every reconciliation in the suite. A\n reconciliation's own comparison settings take precedence, field by field.","uniqueKey":"oneOf.0.suite.comparison.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.suite.comparison","typeLabel":"ComparisonConfig · object | null"}},"title":"suite","required":["name"],"additionalProperties":false,"description":"A suite in the format that Coalesce Quality stores. The request does not\n apply the validation rules of ReconciliationSuite. Thus an incorrect\n suite gets to ValidateSuite, and the response has one issue for each\n rule that the suite does not obey.","isRequired":true,"uniqueKey":"oneOf.0.suite","typeLabel":"suite · object"}},"additionalProperties":false,"uniqueKey":"oneOf.0","typeLabel":"suite · object"},{"type":"object","title":"yaml","required":["yaml"],"properties":{"yaml":{"type":"string","title":"yaml","minLength":1,"description":"A suite in the YAML format of synq-recon. Each issue then has the\n position of its problem in the YAML text.","isRequired":true,"uniqueKey":"oneOf.1.yaml","typeLabel":"string"}},"additionalProperties":false,"uniqueKey":"oneOf.1","typeLabel":"yaml · object"}],"uniqueKey":"","typeLabel":"suite · object | yaml · object"},"examples":{"Example":{"title":"Example","value":{"suite":{"name":"\u003cstring>","title":"\u003cstring>","description":"\u003cstring>","reconciliations":[{"name":"\u003cstring>","source":{"connection":"\u003cstring>","query":"\u003cstring>","asOf":"\u003cstring>","columns":["\u003cstring>"],"excludeColumns":["\u003cstring>"]},"target":{"connection":"\u003cstring>","query":"\u003cstring>","asOf":"\u003cstring>","columns":["\u003cstring>"],"excludeColumns":["\u003cstring>"]},"title":"\u003cstring>","description":"\u003cstring>","keyColumn":"\u003cstring>","keyColumns":["\u003cstring>"],"columnMapping":[{"source":"\u003cstring>","target":"\u003cstring>"}],"caseInsensitive":true,"bisection":{"enabled":true,"factor":513,"threshold":2,"timeColumn":"\u003cstring>"},"reporting":{"sampleLimit":2,"consentAcknowledged":true},"aggregate":{"measures":[{"column":"\u003cstring>","functions":[]}],"thresholds":{"absolute":1,"percentage":1,"perColumn":[{"column":"\u003cstring>","thresholds":"\u003cunknown>"}],"perMeasure":[{"column":"\u003cstring>","thresholds":"\u003cunknown>"}]},"groupColumns":["\u003cstring>"]},"errorHandling":{"queryTimeout":"\u003cstring>","maxRetries":5,"retryInitialDelay":"\u003cstring>","retryBackoffFactor":2},"window":{"lookback":"\u003cstring>","column":"\u003cstring>"},"setup":[{"connection":"\u003cstring>","queries":["\u003cstring>"]}],"teardown":[{"connection":"\u003cstring>","queries":["\u003cstring>"]}],"teardownOnFailure":true,"ignoreSetupErrors":true,"cutoff":{"source":{"column":"\u003cstring>","query":"\u003cstring>"},"target":{"column":"\u003cstring>","query":"\u003cstring>"},"offset":"\u003cstring>","applySource":{"column":"\u003cstring>","operator":"\u003cstring>"},"applyTarget":{"column":"\u003cstring>","operator":"\u003cstring>"}},"annotations":[{"name":"\u003cstring>","values":["\u003cstring>"]}],"timeout":"\u003cstring>","rowCount":{"thresholds":{"absolute":1,"percentage":1,"perColumn":[{"column":"\u003cstring>","thresholds":"\u003cunknown>"}],"perMeasure":[{"column":"\u003cstring>","thresholds":"\u003cunknown>"}]}},"comparison":{"numericScale":{"exact":"true"},"columns":[{"column":"\u003cstring>","numericScale":{"exact":"true"},"sourceTimeZone":"\u003cstring>","targetTimeZone":"\u003cstring>"}],"sourceTimeZone":"\u003cstring>","targetTimeZone":"\u003cstring>"}}],"setup":[{"connection":"\u003cstring>","queries":["\u003cstring>"]}],"teardown":[{"connection":"\u003cstring>","queries":["\u003cstring>"]}],"teardownOnFailure":true,"ignoreSetupErrors":true,"variables":{},"strictTimeReferences":true,"annotations":[{"name":"\u003cstring>","values":["\u003cstring>"]}],"execution":{"timeout":"\u003cstring>","concurrency":32,"reconciliationTimeout":"\u003cstring>"},"comparison":{"numericScale":{"exact":"true"},"columns":[{"column":"\u003cstring>","numericScale":{"exact":"true"},"sourceTimeZone":"\u003cstring>","targetTimeZone":"\u003cstring>"}],"sourceTimeZone":"\u003cstring>","targetTimeZone":"\u003cstring>"}}}}},"exampleType":"generated"}},"required":true,"exampleType":"generated"},"responses":{"bfeb76a8-11aa-4d28-9e9e-e2ecf42b45e1":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean","description":"True when no issue has the ERROR severity. A suite with only warnings is\n valid.","uniqueKey":"valid","typeLabel":"boolean"},"issues":{"type":"array","items":{"type":"object","properties":{"severity":{"type":"string","title":"SuiteValidationSeverity","enum":["SUITE_VALIDATION_SEVERITY_UNSPECIFIED","SUITE_VALIDATION_SEVERITY_ERROR","SUITE_VALIDATION_SEVERITY_WARNING"],"description":"The severity of a SuiteValidationIssue.","uniqueKey":"issues.items.[INDEX].severity","typeLabel":"enum\u003cstring>"},"fieldPath":{"type":"string","description":"The field that has the problem. The path uses the field names of\n ReconciliationSuite, for example\n `reconciliations[2].comparison.columns[0].numeric_scale` or\n `execution.timeout`. The index of a list item is its position in the suite.\n\n A field that only YAML has uses its YAML key, for example\n `reconciliations[0].setup_file`.\n\n The path is empty when the problem is about the full suite, or when the\n YAML text is not valid YAML.","uniqueKey":"issues.items.[INDEX].fieldPath","typeLabel":"string"},"message":{"type":"string","description":"A description of the problem for the person who edits the suite.","uniqueKey":"issues.items.[INDEX].message","typeLabel":"string"},"position":{"oneOf":[{"type":"object","properties":{"line":{"type":"integer","format":"int32","uniqueKey":"issues.items.[INDEX].position.oneOf.0.line","typeLabel":"integer\u003cint32>"},"column":{"type":"integer","format":"int32","uniqueKey":"issues.items.[INDEX].position.oneOf.0.column","typeLabel":"integer\u003cint32>"}},"title":"YamlPosition","additionalProperties":false,"description":"The position of the problem in the YAML text. It is set only when the\n request gives the suite as YAML.\n\n It points to the key of the field in field_path. If the YAML does not have\n that key, for example because a required field is missing, it points to\n the nearest key that contains the field.","uniqueKey":"issues.items.[INDEX].position.oneOf.0","typeLabel":"YamlPosition · object"},{"type":"null","properties":{"line":{"type":"integer","format":"int32"},"column":{"type":"integer","format":"int32"}},"title":"YamlPosition","additionalProperties":false,"description":"The position of the problem in the YAML text. It is set only when the\n request gives the suite as YAML.\n\n It points to the key of the field in field_path. If the YAML does not have\n that key, for example because a required field is missing, it points to\n the nearest key that contains the field.","uniqueKey":"issues.items.[INDEX].position.oneOf.1","typeLabel":"null"}],"uniqueKey":"issues.items.[INDEX].position","typeLabel":"YamlPosition · object | null"}},"title":"SuiteValidationIssue","additionalProperties":false,"description":"One problem in a reconciliation suite.","uniqueKey":"issues.items.[INDEX]","typeLabel":"SuiteValidationIssue · object"},"description":"All the problems in the suite. The errors come first, then the warnings.\n Empty when the suite has no problems.","uniqueKey":"issues","typeLabel":"SuiteValidationIssue · object[]"},"suite":{"oneOf":[{"type":"object","properties":{"name":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9_-]*$","description":"Short machine identifier for the suite.\n Unique machine identifier for the suite, used as the stable key for tracking runs over time.\n Alphanumerics, hyphens, and underscores. May be a UUID.","isRequired":true,"uniqueKey":"suite.oneOf.0.name","typeLabel":"string"},"title":{"oneOf":[{"type":"string","description":"Human-readable title for the suite.\n Displayed in dashboards and reports. Defaults to name when not set.","uniqueKey":"suite.oneOf.0.title.oneOf.0","typeLabel":"string"},{"type":"null","description":"Human-readable title for the suite.\n Displayed in dashboards and reports. Defaults to name when not set.","uniqueKey":"suite.oneOf.0.title.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.title","typeLabel":"string | null"},"description":{"oneOf":[{"type":"string","description":"Optional longer description of the suite's purpose.","uniqueKey":"suite.oneOf.0.description.oneOf.0","typeLabel":"string"},{"type":"null","description":"Optional longer description of the suite's purpose.","uniqueKey":"suite.oneOf.0.description.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.description","typeLabel":"string | null"},"reconciliations":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9_-]*$","description":"Unique machine identifier within the suite. Alphanumerics, hyphens, and underscores. May be a UUID.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].name","typeLabel":"string"},"source":{"oneOf":[{"type":"object","title":"Dataset","description":"Source dataset to compare from — the \"expected\" or \"authoritative\" side.","required":["connection","query"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.0.connection","typeLabel":"string"},"query":{"type":"string","title":"query","description":"Raw SQL query returning the dataset.\n Should be a SELECT or WITH (CTE) statement.\n Supports template variable interpolation via {{variable_name}} syntax.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.0.query","typeLabel":"string"},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.0.asOf.oneOf.0","typeLabel":"string"},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.0.asOf.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.0.asOf","typeLabel":"string | null"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.0.columns.items.[INDEX]","typeLabel":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.0.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.0.excludeColumns.items.[INDEX]","typeLabel":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.0.excludeColumns","typeLabel":"string[]"}},"additionalProperties":false,"isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.0","typeLabel":"Dataset · object"},{"type":"object","title":"Dataset","description":"Source dataset to compare from — the \"expected\" or \"authoritative\" side.","required":["connection","table"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.connection","typeLabel":"string"},"table":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Table or view name (e.g., \"orders\", \"fact_sales\").\n Required — this is the actual object name.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.name","typeLabel":"string"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.columns.items.[INDEX]","typeLabel":"string"},"description":"Explicit list of columns to include in the comparison.\n When set, only these columns are selected from the table.\n Mutually exclusive with exclude_columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.excludeColumns.items.[INDEX]","typeLabel":"string"},"description":"Columns to exclude from the comparison.\n All columns except these are selected (resolved at runtime via table metadata).\n Useful for skipping volatile columns (e.g., updated_at, etl_batch_id).\n Mutually exclusive with columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.excludeColumns","typeLabel":"string[]"},"database":{"oneOf":[{"type":"string","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.database.oneOf.0","typeLabel":"string"},{"type":"null","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.database.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.database","typeLabel":"string | null"},"schema":{"oneOf":[{"type":"string","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.schema.oneOf.0","typeLabel":"string"},{"type":"null","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.schema.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.schema","typeLabel":"string | null"},"where":{"oneOf":[{"type":"string","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\"","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\"","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.where.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table.where","typeLabel":"string | null"}},"title":"table","required":["name"],"additionalProperties":false,"description":"Table reference with optional column selection.\n Automatically generates a SELECT query from the table metadata.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.table","typeLabel":"table · object"},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.asOf.oneOf.0","typeLabel":"string"},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.asOf.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.asOf","typeLabel":"string | null"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.columns.items.[INDEX]","typeLabel":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.excludeColumns.items.[INDEX]","typeLabel":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1.excludeColumns","typeLabel":"string[]"}},"additionalProperties":false,"isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source.oneOf.1","typeLabel":"Dataset · object"}],"isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].source","typeLabel":"Dataset · object"},"target":{"oneOf":[{"type":"object","title":"Dataset","description":"Target dataset to compare against — the \"actual\" or \"replicated\" side.","required":["connection","query"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.0.connection","typeLabel":"string"},"query":{"type":"string","title":"query","description":"Raw SQL query returning the dataset.\n Should be a SELECT or WITH (CTE) statement.\n Supports template variable interpolation via {{variable_name}} syntax.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.0.query","typeLabel":"string"},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.0.asOf.oneOf.0","typeLabel":"string"},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.0.asOf.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.0.asOf","typeLabel":"string | null"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.0.columns.items.[INDEX]","typeLabel":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.0.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.0.excludeColumns.items.[INDEX]","typeLabel":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.0.excludeColumns","typeLabel":"string[]"}},"additionalProperties":false,"isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.0","typeLabel":"Dataset · object"},{"type":"object","title":"Dataset","description":"Target dataset to compare against — the \"actual\" or \"replicated\" side.","required":["connection","table"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.connection","typeLabel":"string"},"table":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Table or view name (e.g., \"orders\", \"fact_sales\").\n Required — this is the actual object name.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.name","typeLabel":"string"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.columns.items.[INDEX]","typeLabel":"string"},"description":"Explicit list of columns to include in the comparison.\n When set, only these columns are selected from the table.\n Mutually exclusive with exclude_columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.excludeColumns.items.[INDEX]","typeLabel":"string"},"description":"Columns to exclude from the comparison.\n All columns except these are selected (resolved at runtime via table metadata).\n Useful for skipping volatile columns (e.g., updated_at, etl_batch_id).\n Mutually exclusive with columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.excludeColumns","typeLabel":"string[]"},"database":{"oneOf":[{"type":"string","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.database.oneOf.0","typeLabel":"string"},{"type":"null","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.database.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.database","typeLabel":"string | null"},"schema":{"oneOf":[{"type":"string","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.schema.oneOf.0","typeLabel":"string"},{"type":"null","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.schema.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.schema","typeLabel":"string | null"},"where":{"oneOf":[{"type":"string","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\"","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\"","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.where.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table.where","typeLabel":"string | null"}},"title":"table","required":["name"],"additionalProperties":false,"description":"Table reference with optional column selection.\n Automatically generates a SELECT query from the table metadata.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.table","typeLabel":"table · object"},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.asOf.oneOf.0","typeLabel":"string"},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.asOf.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.asOf","typeLabel":"string | null"},"columns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.columns.items.[INDEX]","typeLabel":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.columns","typeLabel":"string[]"},"excludeColumns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.excludeColumns.items.[INDEX]","typeLabel":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1.excludeColumns","typeLabel":"string[]"}},"additionalProperties":false,"isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target.oneOf.1","typeLabel":"Dataset · object"}],"isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].target","typeLabel":"Dataset · object"},"title":{"oneOf":[{"type":"string","description":"Human-readable title. Displayed in reports. Defaults to name when not set.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].title.oneOf.0","typeLabel":"string"},{"type":"null","description":"Human-readable title. Displayed in reports. Defaults to name when not set.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].title.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].title","typeLabel":"string | null"},"description":{"oneOf":[{"type":"string","description":"Optional longer description explaining what this reconciliation validates.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].description.oneOf.0","typeLabel":"string"},{"type":"null","description":"Optional longer description explaining what this reconciliation validates.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].description.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].description","typeLabel":"string | null"},"keyColumn":{"oneOf":[{"type":"string","description":"Deprecated: use key_columns instead. Single primary key column used for\n ordering and segmentation during bisection. Retained for backward\n compatibility — existing single-key configs and stored audit logs keep\n working. When key_columns is set, this field is ignored. Readers should\n resolve the effective key via key_columns first, falling back to this.","deprecated":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].keyColumn.oneOf.0","typeLabel":"string"},{"type":"null","description":"Deprecated: use key_columns instead. Single primary key column used for\n ordering and segmentation during bisection. Retained for backward\n compatibility — existing single-key configs and stored audit logs keep\n working. When key_columns is set, this field is ignored. Readers should\n resolve the effective key via key_columns first, falling back to this.","deprecated":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].keyColumn.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].keyColumn","typeLabel":"string | null"},"keyColumns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].keyColumns.items.[INDEX]","typeLabel":"string"},"description":"Ordered list of key columns used for ordering and segmentation during\n bisection. Supports composite (multi-column) keys; the bisection orders and\n range-filters on the column tuple so the engine can prune via a matching\n primary key / index. A single-element list is equivalent to setting\n key_column. Required for ROW_CHECKSUM and ROW_COUNT modes (this or the\n deprecated key_column). Optional in AGGREGATE mode, where it only stands in\n for group_columns when those are unset.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].keyColumns","typeLabel":"string[]"},"mode":{"type":"string","title":"ReconciliationMode","enum":["RECONCILIATION_MODE_UNSPECIFIED","RECONCILIATION_MODE_ROW_COUNT","RECONCILIATION_MODE_ROW_CHECKSUM","RECONCILIATION_MODE_AGGREGATE"],"description":"Comparison mode controlling how source and target are compared.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].mode","typeLabel":"enum\u003cstring>"},"hashAlgorithm":{"oneOf":[{"type":"string","title":"HashAlgorithm","enum":["HASH_ALGORITHM_UNSPECIFIED","HASH_ALGORITHM_MD5","HASH_ALGORITHM_FARM_FINGERPRINT","HASH_ALGORITHM_XXHASH64"],"description":"Hash algorithm for row checksums in ROW_CHECKSUM mode.\n When unset, auto-negotiates the best common algorithm between the\n source and target database dialects.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].hashAlgorithm.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"HashAlgorithm","enum":["HASH_ALGORITHM_UNSPECIFIED","HASH_ALGORITHM_MD5","HASH_ALGORITHM_FARM_FINGERPRINT","HASH_ALGORITHM_XXHASH64"],"description":"Hash algorithm for row checksums in ROW_CHECKSUM mode.\n When unset, auto-negotiates the best common algorithm between the\n source and target database dialects.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].hashAlgorithm.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].hashAlgorithm","typeLabel":"enum\u003cstring> | null"},"columnMapping":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string","minLength":1,"description":"Column name in the source dataset.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].columnMapping.items.[INDEX].source","typeLabel":"string"},"target":{"type":"string","minLength":1,"description":"Corresponding column name in the target dataset.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].columnMapping.items.[INDEX].target","typeLabel":"string"}},"title":"ColumnMapping","required":["source","target"],"additionalProperties":false,"description":"ColumnMapping maps a source column name to a target column name.\n Used when source and target use different naming conventions for the same data\n (e.g., snake_case vs SCREAMING_SNAKE_CASE, or completely different names).\n Only columns with different names need explicit mapping — columns with\n identical names (or case-insensitive matches when case_insensitive is true)\n are matched automatically.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].columnMapping.items.[INDEX]","typeLabel":"ColumnMapping · object"},"description":"Explicit column name mapping between source and target.\n Only columns with different names need mapping — identical names\n (or case-insensitive matches) are matched automatically.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].columnMapping","typeLabel":"ColumnMapping · object[]"},"caseInsensitive":{"oneOf":[{"type":"boolean","description":"When true, automatically matches columns differing only in letter case\n (e.g., user_id matches USER_ID). Defaults to true when not set.\n Set to false to require exact case matching.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].caseInsensitive.oneOf.0","typeLabel":"boolean"},{"type":"null","description":"When true, automatically matches columns differing only in letter case\n (e.g., user_id matches USER_ID). Defaults to true when not set.\n Set to false to require exact case matching.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].caseInsensitive.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].caseInsensitive","typeLabel":"boolean | null"},"bisection":{"oneOf":[{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether bisection drill-down is enabled.\n When false, only the quick-check (count + checksum) runs — mismatches\n are detected but not localized to specific rows.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.enabled","typeLabel":"boolean"},"factor":{"oneOf":[{"type":"integer","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.factor.oneOf.0","typeLabel":"integer\u003cint32>"},{"type":"null","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.factor.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.factor","typeLabel":"integer\u003cint32> | null"},"threshold":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.threshold.oneOf.0","typeLabel":"integer\u003cint32>"},{"type":"null","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.threshold.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.threshold","typeLabel":"integer\u003cint32> | null"},"strategy":{"type":"string","title":"SegmentationStrategy","enum":["SEGMENTATION_STRATEGY_UNSPECIFIED","SEGMENTATION_STRATEGY_QUANTILE","SEGMENTATION_STRATEGY_HASH","SEGMENTATION_STRATEGY_TIME"],"description":"Segmentation strategy for splitting key ranges.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.strategy","typeLabel":"enum\u003cstring>"},"timeColumn":{"oneOf":[{"type":"string","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.timeColumn.oneOf.0","typeLabel":"string"},{"type":"null","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.timeColumn.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.timeColumn","typeLabel":"string | null"},"timeGranularity":{"type":"string","title":"TimeGranularity","enum":["TIME_GRANULARITY_UNSPECIFIED","TIME_GRANULARITY_HOUR","TIME_GRANULARITY_DAY","TIME_GRANULARITY_WEEK","TIME_GRANULARITY_MONTH","TIME_GRANULARITY_QUARTER","TIME_GRANULARITY_YEAR"],"description":"Granularity for time-based segmentation. Default: DAY.\n Controls the width of each time bucket when strategy is TIME.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0.timeGranularity","typeLabel":"enum\u003cstring>"}},"title":"BisectionConfig","additionalProperties":false,"description":"Bisection drill-down configuration for ROW_CHECKSUM mode.\n Controls how the key range is recursively split to locate mismatches.\n When not set, uses sensible defaults (factor=32, threshold=16384).","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.0","typeLabel":"BisectionConfig · object"},{"type":"null","properties":{"enabled":{"type":"boolean","description":"Whether bisection drill-down is enabled.\n When false, only the quick-check (count + checksum) runs — mismatches\n are detected but not localized to specific rows."},"factor":{"oneOf":[{"type":"integer","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64."},{"type":"null","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64."}]},"threshold":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows."},{"type":"null","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows."}]},"strategy":{"type":"string","title":"SegmentationStrategy","enum":["SEGMENTATION_STRATEGY_UNSPECIFIED","SEGMENTATION_STRATEGY_QUANTILE","SEGMENTATION_STRATEGY_HASH","SEGMENTATION_STRATEGY_TIME"],"description":"Segmentation strategy for splitting key ranges."},"timeColumn":{"oneOf":[{"type":"string","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset."},{"type":"null","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset."}]},"timeGranularity":{"type":"string","title":"TimeGranularity","enum":["TIME_GRANULARITY_UNSPECIFIED","TIME_GRANULARITY_HOUR","TIME_GRANULARITY_DAY","TIME_GRANULARITY_WEEK","TIME_GRANULARITY_MONTH","TIME_GRANULARITY_QUARTER","TIME_GRANULARITY_YEAR"],"description":"Granularity for time-based segmentation. Default: DAY.\n Controls the width of each time bucket when strategy is TIME."}},"title":"BisectionConfig","additionalProperties":false,"description":"Bisection drill-down configuration for ROW_CHECKSUM mode.\n Controls how the key range is recursively split to locate mismatches.\n When not set, uses sensible defaults (factor=32, threshold=16384).","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].bisection","typeLabel":"BisectionConfig · object | null"},"reporting":{"oneOf":[{"type":"object","properties":{"level":{"type":"string","title":"MismatchDetailLevel","enum":["MISMATCH_DETAIL_LEVEL_UNSPECIFIED","MISMATCH_DETAIL_LEVEL_COUNT_ONLY","MISMATCH_DETAIL_LEVEL_WITH_KEYS","MISMATCH_DETAIL_LEVEL_DETAILED"],"description":"Output detail level for mismatched rows.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].reporting.oneOf.0.level","typeLabel":"enum\u003cstring>"},"sampleLimit":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].reporting.oneOf.0.sampleLimit.oneOf.0","typeLabel":"integer\u003cint32>"},{"type":"null","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].reporting.oneOf.0.sampleLimit.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].reporting.oneOf.0.sampleLimit","typeLabel":"integer\u003cint32> | null"},"consentAcknowledged":{"type":"boolean","description":"Explicit acknowledgment that detailed row data may be included in the audit log.\n Required when level is DETAILED to prevent accidental exposure of sensitive data.\n The caller must set this to true to confirm they understand the privacy implications.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].reporting.oneOf.0.consentAcknowledged","typeLabel":"boolean"}},"title":"ReportingConfig","additionalProperties":false,"description":"Reporting output configuration controlling how much detail is included\n in the audit log for mismatched rows.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].reporting.oneOf.0","typeLabel":"ReportingConfig · object"},{"type":"null","properties":{"level":{"type":"string","title":"MismatchDetailLevel","enum":["MISMATCH_DETAIL_LEVEL_UNSPECIFIED","MISMATCH_DETAIL_LEVEL_COUNT_ONLY","MISMATCH_DETAIL_LEVEL_WITH_KEYS","MISMATCH_DETAIL_LEVEL_DETAILED"],"description":"Output detail level for mismatched rows."},"sampleLimit":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included."},{"type":"null","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included."}]},"consentAcknowledged":{"type":"boolean","description":"Explicit acknowledgment that detailed row data may be included in the audit log.\n Required when level is DETAILED to prevent accidental exposure of sensitive data.\n The caller must set this to true to confirm they understand the privacy implications."}},"title":"ReportingConfig","additionalProperties":false,"description":"Reporting output configuration controlling how much detail is included\n in the audit log for mismatched rows.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].reporting.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].reporting","typeLabel":"ReportingConfig · object | null"},"aggregate":{"oneOf":[{"type":"object","properties":{"measures":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name to aggregate. Must exist in both source and target datasets\n (after column mapping is applied).","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.measures.items.[INDEX].column","typeLabel":"string"},"functions":{"type":"array","items":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"AggregateFunction defines the supported SQL aggregate functions\n for measure comparisons in aggregate reconciliation mode.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.measures.items.[INDEX].functions.items.[INDEX]","typeLabel":"enum\u003cstring>"},"minItems":1,"description":"Aggregate functions to apply to this column.\n Multiple functions produce multiple measure comparisons from one column.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.measures.items.[INDEX].functions","typeLabel":"enum\u003cstring>[]"}},"title":"Measure","required":["column"],"additionalProperties":false,"description":"Measure defines a column and aggregate function(s) to compare\n between source and target datasets.\n A single measure with multiple functions expands into multiple comparisons\n (e.g., column=\"amount\" functions=[SUM, AVG] produces \"SUM(amount)\" and \"AVG(amount)\").","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.measures.items.[INDEX]","typeLabel":"Measure · object"},"minItems":1,"description":"Measures to compare between source and target.\n Each measure defines a column and one or more aggregate functions to apply.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.measures","typeLabel":"Measure · object[]"},"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.absolute.oneOf.0","typeLabel":"number\u003cdouble>"},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.absolute.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.absolute","typeLabel":"number\u003cdouble> | null"},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.percentage.oneOf.0","typeLabel":"number\u003cdouble>"},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.percentage.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.percentage","typeLabel":"number\u003cdouble> | null"},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.percentageBasis","typeLabel":"enum\u003cstring>"},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX].column","typeLabel":"string"},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX].thresholds","typeLabel":"any"}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX]","typeLabel":"ColumnThresholdOverride · object"},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perColumn","typeLabel":"ColumnThresholdOverride · object[]"},"perMeasure":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\").","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].column","typeLabel":"string"},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].thresholds","typeLabel":"any"},"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].function","typeLabel":"enum\u003cstring>"}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination).","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX]","typeLabel":"MeasureThresholdOverride · object"},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0.perMeasure","typeLabel":"MeasureThresholdOverride · object[]"}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.0","typeLabel":"ThresholdConfig · object"},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.thresholds","typeLabel":"ThresholdConfig · object | null"},"groupColumns":{"type":"array","items":{"type":"string","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.groupColumns.items.[INDEX]","typeLabel":"string"},"description":"Columns defining the drill-down hierarchy for aggregate comparison.\n Falls back to the key columns if not set. With no key columns either, the\n whole dataset is compared as a single group, with no GROUP BY.\n\n Single column: flat GROUP BY comparison.\n group_columns: [\"region\"]\n → GROUP BY region\n\n Multiple columns: cumulative GROUP BY drill-down, pruning matched groups\n at each level to focus on divergent branches.\n group_columns: [\"region\", \"city\", \"store\"]\n → Level 0: GROUP BY region\n → Level 1: GROUP BY region, city (only for mismatched regions)\n → Level 2: GROUP BY region, city, store (only for mismatched cities)","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0.groupColumns","typeLabel":"string[]"}},"title":"AggregateConfig","additionalProperties":false,"description":"Aggregate comparison settings. Required when mode is AGGREGATE.\n Defines which measures to compare and tolerance thresholds.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.0","typeLabel":"AggregateConfig · object"},{"type":"null","properties":{"measures":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name to aggregate. Must exist in both source and target datasets\n (after column mapping is applied)."},"functions":{"type":"array","items":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"AggregateFunction defines the supported SQL aggregate functions\n for measure comparisons in aggregate reconciliation mode."},"minItems":1,"description":"Aggregate functions to apply to this column.\n Multiple functions produce multiple measure comparisons from one column."}},"title":"Measure","required":["column"],"additionalProperties":false,"description":"Measure defines a column and aggregate function(s) to compare\n between source and target datasets.\n A single measure with multiple functions expands into multiple comparisons\n (e.g., column=\"amount\" functions=[SUM, AVG] produces \"SUM(amount)\" and \"AVG(amount)\")."},"minItems":1,"description":"Measures to compare between source and target.\n Each measure defines a column and one or more aggregate functions to apply."},"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures."},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures."}]},"groupColumns":{"type":"array","items":{"type":"string"},"description":"Columns defining the drill-down hierarchy for aggregate comparison.\n Falls back to the key columns if not set. With no key columns either, the\n whole dataset is compared as a single group, with no GROUP BY.\n\n Single column: flat GROUP BY comparison.\n group_columns: [\"region\"]\n → GROUP BY region\n\n Multiple columns: cumulative GROUP BY drill-down, pruning matched groups\n at each level to focus on divergent branches.\n group_columns: [\"region\", \"city\", \"store\"]\n → Level 0: GROUP BY region\n → Level 1: GROUP BY region, city (only for mismatched regions)\n → Level 2: GROUP BY region, city, store (only for mismatched cities)"}},"title":"AggregateConfig","additionalProperties":false,"description":"Aggregate comparison settings. Required when mode is AGGREGATE.\n Defines which measures to compare and tolerance thresholds.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].aggregate","typeLabel":"AggregateConfig · object | null"},"errorHandling":{"oneOf":[{"type":"object","properties":{"queryTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.queryTimeout.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.queryTimeout.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.queryTimeout","typeLabel":"string\u003cduration> | null"},"maxRetries":{"oneOf":[{"type":"integer","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.maxRetries.oneOf.0","typeLabel":"integer\u003cint32>"},{"type":"null","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.maxRetries.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.maxRetries","typeLabel":"integer\u003cint32> | null"},"retryInitialDelay":{"oneOf":[{"type":"string","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryInitialDelay.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryInitialDelay.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryInitialDelay","typeLabel":"string\u003cduration> | null"},"retryBackoffFactor":{"oneOf":[{"type":"number","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryBackoffFactor.oneOf.0","typeLabel":"number\u003cdouble>"},{"type":"null","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryBackoffFactor.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0.retryBackoffFactor","typeLabel":"number\u003cdouble> | null"}},"title":"ErrorHandlingConfig","additionalProperties":false,"description":"Error handling and retry configuration for database queries.\n Controls timeouts and retry behavior for transient failures.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.0","typeLabel":"ErrorHandlingConfig · object"},{"type":"null","properties":{"queryTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit."},{"type":"null","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit."}]},"maxRetries":{"oneOf":[{"type":"integer","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2."},{"type":"null","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2."}]},"retryInitialDelay":{"oneOf":[{"type":"string","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s."},{"type":"null","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s."}]},"retryBackoffFactor":{"oneOf":[{"type":"number","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0."},{"type":"null","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0."}]}},"title":"ErrorHandlingConfig","additionalProperties":false,"description":"Error handling and retry configuration for database queries.\n Controls timeouts and retry behavior for transient failures.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].errorHandling","typeLabel":"ErrorHandlingConfig · object | null"},"window":{"oneOf":[{"type":"object","properties":{"lookback":{"type":"string","format":"duration","description":"How far back to look from the current time.\n Defines the window as [now - lookback, now].\n Examples: \"336h\" (14 days), \"2h\", \"720h\" (30 days).","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].window.oneOf.0.lookback","typeLabel":"string\u003cduration>"},"column":{"oneOf":[{"type":"string","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].window.oneOf.0.column.oneOf.0","typeLabel":"string"},{"type":"null","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].window.oneOf.0.column.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].window.oneOf.0.column","typeLabel":"string | null"},"strategy":{"type":"string","title":"WindowStrategy","enum":["WINDOW_STRATEGY_UNSPECIFIED","WINDOW_STRATEGY_SLIDING","WINDOW_STRATEGY_FIXED"],"description":"Windowing strategy controlling how boundaries are computed.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].window.oneOf.0.strategy","typeLabel":"enum\u003cstring>"}},"title":"WindowConfig","required":["lookback"],"additionalProperties":false,"description":"Time window for incremental comparison.\n When set, automatically provides a {{window_start}} template variable\n for filtering queries to a recent time range.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].window.oneOf.0","typeLabel":"WindowConfig · object"},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause."},{"type":"null","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause."}]},"lookback":{"type":"string","format":"duration","description":"How far back to look from the current time.\n Defines the window as [now - lookback, now].\n Examples: \"336h\" (14 days), \"2h\", \"720h\" (30 days)."},"strategy":{"type":"string","title":"WindowStrategy","enum":["WINDOW_STRATEGY_UNSPECIFIED","WINDOW_STRATEGY_SLIDING","WINDOW_STRATEGY_FIXED"],"description":"Windowing strategy controlling how boundaries are computed."}},"title":"WindowConfig","required":["lookback"],"additionalProperties":false,"description":"Time window for incremental comparison.\n When set, automatically provides a {{window_start}} template variable\n for filtering queries to a recent time range.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].window.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].window","typeLabel":"WindowConfig · object | null"},"setup":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].setup.items.[INDEX].connection","typeLabel":"string"},"queries":{"type":"array","items":{"type":"string","minItems":1,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].setup.items.[INDEX].queries.items.[INDEX]","typeLabel":"string"},"minItems":1,"description":"SQL queries to execute in order on this connection.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].setup.items.[INDEX].queries","typeLabel":"string[]"}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].setup.items.[INDEX]","typeLabel":"ConnectionQueries · object"},"description":"Setup queries run before this specific reconciliation.\n Executes after suite-level setup but before data comparison.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].setup","typeLabel":"ConnectionQueries · object[]"},"teardown":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].teardown.items.[INDEX].connection","typeLabel":"string"},"queries":{"type":"array","items":{"type":"string","minItems":1,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].teardown.items.[INDEX].queries.items.[INDEX]","typeLabel":"string"},"minItems":1,"description":"SQL queries to execute in order on this connection.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].teardown.items.[INDEX].queries","typeLabel":"string[]"}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].teardown.items.[INDEX]","typeLabel":"ConnectionQueries · object"},"description":"Teardown queries run after this specific reconciliation completes.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].teardown","typeLabel":"ConnectionQueries · object[]"},"teardownOnFailure":{"oneOf":[{"type":"boolean","description":"Whether teardown runs on failure for this reconciliation.\n When not set, inherits from suite-level teardown_on_failure.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].teardownOnFailure.oneOf.0","typeLabel":"boolean"},{"type":"null","description":"Whether teardown runs on failure for this reconciliation.\n When not set, inherits from suite-level teardown_on_failure.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].teardownOnFailure.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].teardownOnFailure","typeLabel":"boolean | null"},"ignoreSetupErrors":{"oneOf":[{"type":"boolean","description":"When true, logs setup errors as warnings and continues.\n When not set, inherits from suite-level ignore_setup_errors.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].ignoreSetupErrors.oneOf.0","typeLabel":"boolean"},{"type":"null","description":"When true, logs setup errors as warnings and continues.\n When not set, inherits from suite-level ignore_setup_errors.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].ignoreSetupErrors.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].ignoreSetupErrors","typeLabel":"boolean | null"},"cutoff":{"oneOf":[{"type":"object","properties":{"source":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0.column","typeLabel":"string"},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0.aggregate","typeLabel":"enum\u003cstring>"},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0.query.oneOf.0","typeLabel":"string"},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0.query.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0.query","typeLabel":"string | null"}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.0","typeLabel":"CutoffSideConfig · object"},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.source.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.source","typeLabel":"CutoffSideConfig · object | null"},"target":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0.column","typeLabel":"string"},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0.aggregate","typeLabel":"enum\u003cstring>"},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0.query.oneOf.0","typeLabel":"string"},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0.query.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0.query","typeLabel":"string | null"}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.0","typeLabel":"CutoffSideConfig · object"},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.target.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.target","typeLabel":"CutoffSideConfig · object | null"},"combine":{"type":"string","title":"CutoffCombineStrategy","enum":["CUTOFF_COMBINE_STRATEGY_UNSPECIFIED","CUTOFF_COMBINE_STRATEGY_MIN","CUTOFF_COMBINE_STRATEGY_MAX","CUTOFF_COMBINE_STRATEGY_SOURCE","CUTOFF_COMBINE_STRATEGY_TARGET"],"description":"How to combine watermarks when both sides are configured.\n Default: MIN (use the smaller watermark for safety).\n Ignored when only one side has a watermark.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.combine","typeLabel":"enum\u003cstring>"},"truncate":{"type":"string","title":"CutoffTruncateUnit","enum":["CUTOFF_TRUNCATE_UNIT_UNSPECIFIED","CUTOFF_TRUNCATE_UNIT_HOUR","CUTOFF_TRUNCATE_UNIT_DAY","CUTOFF_TRUNCATE_UNIT_WEEK","CUTOFF_TRUNCATE_UNIT_MONTH","CUTOFF_TRUNCATE_UNIT_QUARTER","CUTOFF_TRUNCATE_UNIT_YEAR"],"description":"Truncate the combined watermark to a time boundary.\n Example: HOUR truncates 08:47:12 to 08:00:00.\n Applied after combining, before offset.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.truncate","typeLabel":"enum\u003cstring>"},"offset":{"oneOf":[{"type":"string","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.offset.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.offset.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.offset","typeLabel":"string\u003cduration> | null"},"applySource":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.column.oneOf.0","typeLabel":"string"},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.column.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.column","typeLabel":"string | null"},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\".","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.operator.oneOf.0","typeLabel":"string"},{"type":"null","description":"Comparison operator. Default: \"\u003c=\".","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.operator.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0.operator","typeLabel":"string | null"}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.0","typeLabel":"CutoffApplyConfig · object"},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applySource","typeLabel":"CutoffApplyConfig · object | null"},"applyTarget":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.column.oneOf.0","typeLabel":"string"},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.column.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.column","typeLabel":"string | null"},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\".","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.operator.oneOf.0","typeLabel":"string"},{"type":"null","description":"Comparison operator. Default: \"\u003c=\".","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.operator.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0.operator","typeLabel":"string | null"}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.0","typeLabel":"CutoffApplyConfig · object"},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0.applyTarget","typeLabel":"CutoffApplyConfig · object | null"}},"title":"CutoffConfig","additionalProperties":false,"description":"Dynamic cutoff filter for sync reconciliation.\n Derives a watermark from actual data to exclude rows not yet synced.\n Applied as WHERE filter to both source and target queries at runtime.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.0","typeLabel":"CutoffConfig · object"},{"type":"null","properties":{"source":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only."},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only."}]},"target":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only."},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only."}]},"combine":{"type":"string","title":"CutoffCombineStrategy","enum":["CUTOFF_COMBINE_STRATEGY_UNSPECIFIED","CUTOFF_COMBINE_STRATEGY_MIN","CUTOFF_COMBINE_STRATEGY_MAX","CUTOFF_COMBINE_STRATEGY_SOURCE","CUTOFF_COMBINE_STRATEGY_TARGET"],"description":"How to combine watermarks when both sides are configured.\n Default: MIN (use the smaller watermark for safety).\n Ignored when only one side has a watermark."},"truncate":{"type":"string","title":"CutoffTruncateUnit","enum":["CUTOFF_TRUNCATE_UNIT_UNSPECIFIED","CUTOFF_TRUNCATE_UNIT_HOUR","CUTOFF_TRUNCATE_UNIT_DAY","CUTOFF_TRUNCATE_UNIT_WEEK","CUTOFF_TRUNCATE_UNIT_MONTH","CUTOFF_TRUNCATE_UNIT_QUARTER","CUTOFF_TRUNCATE_UNIT_YEAR"],"description":"Truncate the combined watermark to a time boundary.\n Example: HOUR truncates 08:47:12 to 08:00:00.\n Applied after combining, before offset."},"offset":{"oneOf":[{"type":"string","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier."},{"type":"null","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier."}]},"applySource":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator."},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator."}]},"applyTarget":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator."},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator."}]}},"title":"CutoffConfig","additionalProperties":false,"description":"Dynamic cutoff filter for sync reconciliation.\n Derives a watermark from actual data to exclude rows not yet synced.\n Applied as WHERE filter to both source and target queries at runtime.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].cutoff","typeLabel":"CutoffConfig · object | null"},"annotations":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"minLength":1,"description":"String key for the annotation.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].annotations.items.[INDEX].name","typeLabel":"string"},"values":{"type":"array","items":{"type":"string","maxLength":100,"minLength":1,"maxItems":20,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].annotations.items.[INDEX].values.items.[INDEX]","typeLabel":"string"},"maxItems":20,"description":"Optional list of values that the annotation can carry.\n\n A value is something entities are filtered and searched by, not free-form\n metadata, so keep it to a label a person would pick out of a list. The limit\n is set to hold an identifier or a link the annotated system generated —\n truncating one of those produces a value that no longer resolves, and no\n longer matches the filter it exists for. Put prose in the entity\n description instead.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].annotations.items.[INDEX].values","typeLabel":"string[]"}},"title":"Annotation","required":["name"],"additionalProperties":false,"description":"Annotations can be used to annotate any entity with a key:value pair.\n These annotations can be used for filtering and searching entities.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].annotations.items.[INDEX]","typeLabel":"Annotation · object"},"description":"Case-level annotations. Merged with suite-level annotations and\n deployment-level annotations at promote time, then exposed on the\n case asset (PromotedReconCaseMetadata).","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].annotations","typeLabel":"Annotation · object[]"},"timeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for this reconciliation: its setup, quick check\n and any drill. Overrides the suite's execution.reconciliation_timeout.\n A reconciliation that exceeds it is recorded as failed with a timeout\n error and the run moves on to the next one. It never extends the run's\n own timeout. For a bound on each individual query, use\n error_handling.query_timeout.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].timeout.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Maximum wall-clock time for this reconciliation: its setup, quick check\n and any drill. Overrides the suite's execution.reconciliation_timeout.\n A reconciliation that exceeds it is recorded as failed with a timeout\n error and the run moves on to the next one. It never extends the run's\n own timeout. For a bound on each individual query, use\n error_handling.query_timeout.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].timeout.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].timeout","typeLabel":"string\u003cduration> | null"},"rowCount":{"oneOf":[{"type":"object","properties":{"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.absolute.oneOf.0","typeLabel":"number\u003cdouble>"},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.absolute.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.absolute","typeLabel":"number\u003cdouble> | null"},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.percentage.oneOf.0","typeLabel":"number\u003cdouble>"},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.percentage.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.percentage","typeLabel":"number\u003cdouble> | null"},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.percentageBasis","typeLabel":"enum\u003cstring>"},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX].column","typeLabel":"string"},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX].thresholds","typeLabel":"any"}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perColumn.items.[INDEX]","typeLabel":"ColumnThresholdOverride · object"},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perColumn","typeLabel":"ColumnThresholdOverride · object[]"},"perMeasure":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\").","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].column","typeLabel":"string"},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].thresholds","typeLabel":"any"},"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX].function","typeLabel":"enum\u003cstring>"}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination).","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perMeasure.items.[INDEX]","typeLabel":"MeasureThresholdOverride · object"},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0.perMeasure","typeLabel":"MeasureThresholdOverride · object[]"}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.0","typeLabel":"ThresholdConfig · object"},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0.thresholds","typeLabel":"ThresholdConfig · object | null"}},"title":"RowCountConfig","additionalProperties":false,"description":"Row count comparison settings. Only used when mode is ROW_COUNT.\n Sets the tolerance a difference in row counts may stay within.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.0","typeLabel":"RowCountConfig · object"},{"type":"null","properties":{"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal."},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal."}]}},"title":"RowCountConfig","additionalProperties":false,"description":"Row count comparison settings. Only used when mode is ROW_COUNT.\n Sets the tolerance a difference in row counts may stay within.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].rowCount","typeLabel":"RowCountConfig · object | null"},"comparison":{"oneOf":[{"type":"object","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale.oneOf.0.exact","typeLabel":"boolean"}},"additionalProperties":false,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale.oneOf.0","typeLabel":"exact · object"},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale.oneOf.1.places","typeLabel":"integer\u003cint32>"}},"additionalProperties":false,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale.oneOf.1","typeLabel":"places · object"},{"type":"null","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale.oneOf.2","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.numericScale","typeLabel":"exact · object | places · object | null"},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].column","typeLabel":"string"},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.0.exact","typeLabel":"boolean"}},"additionalProperties":false,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.0","typeLabel":"exact · object"},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one.","isRequired":true,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.1.places","typeLabel":"integer\u003cint32>"}},"additionalProperties":false,"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.1","typeLabel":"places · object"},{"type":"null","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.2","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].numericScale","typeLabel":"exact · object | places · object | null"},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].timestampPrecision.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].timestampPrecision.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].timestampPrecision","typeLabel":"enum\u003cstring> | null"},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone","typeLabel":"string | null"},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].targetTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].targetTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX].targetTimeZone","typeLabel":"string | null"}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns.items.[INDEX]","typeLabel":"ColumnComparison · object"},"description":"Settings for individual columns, overriding the settings above.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.columns","typeLabel":"ColumnComparison · object[]"},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.timestampPrecision.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.timestampPrecision.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.timestampPrecision","typeLabel":"enum\u003cstring> | null"},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.sourceTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.sourceTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.sourceTimeZone","typeLabel":"string | null"},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.targetTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.targetTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0.targetTimeZone","typeLabel":"string | null"}},"title":"ComparisonConfig","additionalProperties":false,"description":"How column values are compared in ROW_CHECKSUM mode. Overrides the suite's\n comparison settings. When not set, the suite's apply, and without those\n every column is compared at the precision its types on both sides allow.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.0","typeLabel":"ComparisonConfig · object"},{"type":"null","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair."},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."}]}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column."},"description":"Settings for individual columns, overriding the settings above."},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."}]}},"title":"ComparisonConfig","additionalProperties":false,"description":"How column values are compared in ROW_CHECKSUM mode. Overrides the suite's\n comparison settings. When not set, the suite's apply, and without those\n every column is compared at the precision its types on both sides allow.","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX].comparison","typeLabel":"ComparisonConfig · object | null"}},"title":"Reconciliation","required":["name","source","target"],"additionalProperties":false,"description":"Reconciliation defines a single reconciliation scenario comparing data\n between a source and target dataset. Each reconciliation runs independently\n and produces its own pass/mismatch/fail result.\naggregate_config_required // aggregate config is required when mode is AGGREGATE\nkey_column_and_key_columns_mutually_exclusive // set either key_column (single) or key_columns (composite), not both\nkey_column_required_for_non_aggregate // key_column or key_columns is required unless mode is AGGREGATE\n","uniqueKey":"suite.oneOf.0.reconciliations.items.[INDEX]","typeLabel":"Reconciliation · object"},"minItems":1,"description":"Reconciliation scenarios to execute.\n Each reconciliation compares data between a source and target dataset.","uniqueKey":"suite.oneOf.0.reconciliations","typeLabel":"Reconciliation · object[]"},"setup":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map.","isRequired":true,"uniqueKey":"suite.oneOf.0.setup.items.[INDEX].connection","typeLabel":"string"},"queries":{"type":"array","items":{"type":"string","minItems":1,"uniqueKey":"suite.oneOf.0.setup.items.[INDEX].queries.items.[INDEX]","typeLabel":"string"},"minItems":1,"description":"SQL queries to execute in order on this connection.","uniqueKey":"suite.oneOf.0.setup.items.[INDEX].queries","typeLabel":"string[]"}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level.","uniqueKey":"suite.oneOf.0.setup.items.[INDEX]","typeLabel":"ConnectionQueries · object"},"description":"Setup queries run once before all reconciliations begin.\n Use for creating temp tables, loading fixtures, or preparing the environment.\n Queries execute in order; all connections run sequentially.","uniqueKey":"suite.oneOf.0.setup","typeLabel":"ConnectionQueries · object[]"},"teardown":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map.","isRequired":true,"uniqueKey":"suite.oneOf.0.teardown.items.[INDEX].connection","typeLabel":"string"},"queries":{"type":"array","items":{"type":"string","minItems":1,"uniqueKey":"suite.oneOf.0.teardown.items.[INDEX].queries.items.[INDEX]","typeLabel":"string"},"minItems":1,"description":"SQL queries to execute in order on this connection.","uniqueKey":"suite.oneOf.0.teardown.items.[INDEX].queries","typeLabel":"string[]"}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level.","uniqueKey":"suite.oneOf.0.teardown.items.[INDEX]","typeLabel":"ConnectionQueries · object"},"description":"Teardown queries run once after all reconciliations complete.\n Use for cleaning up temp tables or restoring state.","uniqueKey":"suite.oneOf.0.teardown","typeLabel":"ConnectionQueries · object[]"},"teardownOnFailure":{"type":"boolean","description":"Whether teardown runs even when reconciliations fail with infrastructure errors.\n When false (default), teardown is skipped on failure to preserve state for debugging.","uniqueKey":"suite.oneOf.0.teardownOnFailure","typeLabel":"boolean"},"ignoreSetupErrors":{"type":"boolean","description":"When true, logs setup query errors as warnings and continues execution\n instead of aborting the run. Useful when setup creates IF NOT EXISTS objects.","uniqueKey":"suite.oneOf.0.ignoreSetupErrors","typeLabel":"boolean"},"variables":{"type":"object","additionalProperties":{"type":"string","title":"value","uniqueKey":"suite.oneOf.0.variables.additionalProperties","typeLabel":"string"},"description":"Template variables for query interpolation via {{variable_name}} syntax.\n Values can be literal strings or template expressions:\n - Literal: \"2026-01-01\"\n - Time expression: \"{{today - 30d}}\", \"{{now - 2h}}\"\n - Built-in: \"{{now}}\", \"{{today}}\", \"{{window_start}}\"\n Variables are resolved once at the start of the run and frozen.","uniqueKey":"suite.oneOf.0.variables","typeLabel":"object"},"strictTimeReferences":{"type":"boolean","description":"When true, time reference detection (e.g. NOW(), CURRENT_DATE, GETDATE()\n in queries) returns an error instead of a warning. Prevents non-deterministic\n queries that produce different results on each run.","uniqueKey":"suite.oneOf.0.strictTimeReferences","typeLabel":"boolean"},"annotations":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"minLength":1,"description":"String key for the annotation.","isRequired":true,"uniqueKey":"suite.oneOf.0.annotations.items.[INDEX].name","typeLabel":"string"},"values":{"type":"array","items":{"type":"string","maxLength":100,"minLength":1,"maxItems":20,"uniqueKey":"suite.oneOf.0.annotations.items.[INDEX].values.items.[INDEX]","typeLabel":"string"},"maxItems":20,"description":"Optional list of values that the annotation can carry.\n\n A value is something entities are filtered and searched by, not free-form\n metadata, so keep it to a label a person would pick out of a list. The limit\n is set to hold an identifier or a link the annotated system generated —\n truncating one of those produces a value that no longer resolves, and no\n longer matches the filter it exists for. Put prose in the entity\n description instead.","uniqueKey":"suite.oneOf.0.annotations.items.[INDEX].values","typeLabel":"string[]"}},"title":"Annotation","required":["name"],"additionalProperties":false,"description":"Annotations can be used to annotate any entity with a key:value pair.\n These annotations can be used for filtering and searching entities.","uniqueKey":"suite.oneOf.0.annotations.items.[INDEX]","typeLabel":"Annotation · object"},"description":"Suite-level annotations. Each annotation is a name with zero or more\n string values. Applied to the deployed suite asset and inherited by every\n reconciliation case under the suite. Merged with per-case annotations and\n deployment-level annotations at promote time — the final, deduplicated\n list is exposed on PromotedReconSuiteMetadata / PromotedReconCaseMetadata\n and surfaced to the rest of the SYNQ platform via EntityAnnotations.","uniqueKey":"suite.oneOf.0.annotations","typeLabel":"Annotation · object[]"},"execution":{"oneOf":[{"type":"object","properties":{"timeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"suite.oneOf.0.execution.oneOf.0.timeout.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"suite.oneOf.0.execution.oneOf.0.timeout.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.execution.oneOf.0.timeout","typeLabel":"string\u003cduration> | null"},"concurrency":{"oneOf":[{"type":"integer","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum.","uniqueKey":"suite.oneOf.0.execution.oneOf.0.concurrency.oneOf.0","typeLabel":"integer\u003cint32>"},{"type":"null","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum.","uniqueKey":"suite.oneOf.0.execution.oneOf.0.concurrency.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.execution.oneOf.0.concurrency","typeLabel":"integer\u003cint32> | null"},"reconciliationTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"suite.oneOf.0.execution.oneOf.0.reconciliationTimeout.oneOf.0","typeLabel":"string\u003cduration>"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n","uniqueKey":"suite.oneOf.0.execution.oneOf.0.reconciliationTimeout.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.execution.oneOf.0.reconciliationTimeout","typeLabel":"string\u003cduration> | null"}},"title":"ExecutionConfig","additionalProperties":false,"description":"How runs of this suite execute: the wall-clock budget of a run and how\n many reconciliations run at the same time. Read by every run of the\n suite, local or server-side; a run-level override (a CLI flag, the\n execution_timeout on a trigger or on a deployment) takes precedence.","uniqueKey":"suite.oneOf.0.execution.oneOf.0","typeLabel":"ExecutionConfig · object"},{"type":"null","properties":{"timeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"}]},"concurrency":{"oneOf":[{"type":"integer","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum."},{"type":"null","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum."}]},"reconciliationTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"}]}},"title":"ExecutionConfig","additionalProperties":false,"description":"How runs of this suite execute: the wall-clock budget of a run and how\n many reconciliations run at the same time. Read by every run of the\n suite, local or server-side; a run-level override (a CLI flag, the\n execution_timeout on a trigger or on a deployment) takes precedence.","uniqueKey":"suite.oneOf.0.execution.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.execution","typeLabel":"ExecutionConfig · object | null"},"comparison":{"oneOf":[{"type":"object","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true","isRequired":true,"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.numericScale.oneOf.0.exact","typeLabel":"boolean"}},"additionalProperties":false,"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.numericScale.oneOf.0","typeLabel":"exact · object"},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one.","isRequired":true,"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.numericScale.oneOf.1.places","typeLabel":"integer\u003cint32>"}},"additionalProperties":false,"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.numericScale.oneOf.1","typeLabel":"places · object"},{"type":"null","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.numericScale.oneOf.2","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.numericScale","typeLabel":"exact · object | places · object | null"},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair.","isRequired":true,"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].column","typeLabel":"string"},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true","isRequired":true,"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.0.exact","typeLabel":"boolean"}},"additionalProperties":false,"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.0","typeLabel":"exact · object"},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one.","isRequired":true,"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.1.places","typeLabel":"integer\u003cint32>"}},"additionalProperties":false,"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.1","typeLabel":"places · object"},{"type":"null","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].numericScale.oneOf.2","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].numericScale","typeLabel":"exact · object | places · object | null"},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].timestampPrecision.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].timestampPrecision.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].timestampPrecision","typeLabel":"enum\u003cstring> | null"},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].sourceTimeZone","typeLabel":"string | null"},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].targetTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].targetTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX].targetTimeZone","typeLabel":"string | null"}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns.items.[INDEX]","typeLabel":"ColumnComparison · object"},"description":"Settings for individual columns, overriding the settings above.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.columns","typeLabel":"ColumnComparison · object[]"},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.timestampPrecision.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]},"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.timestampPrecision.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.timestampPrecision","typeLabel":"enum\u003cstring> | null"},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.sourceTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.sourceTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.sourceTimeZone","typeLabel":"string | null"},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.targetTimeZone.oneOf.0","typeLabel":"string"},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0.targetTimeZone.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.comparison.oneOf.0.targetTimeZone","typeLabel":"string | null"}},"title":"ComparisonConfig","additionalProperties":false,"description":"Default comparison settings for every reconciliation in the suite. A\n reconciliation's own comparison settings take precedence, field by field.","uniqueKey":"suite.oneOf.0.comparison.oneOf.0","typeLabel":"ComparisonConfig · object"},{"type":"null","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair."},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."}]}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column."},"description":"Settings for individual columns, overriding the settings above."},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."}]}},"title":"ComparisonConfig","additionalProperties":false,"description":"Default comparison settings for every reconciliation in the suite. A\n reconciliation's own comparison settings take precedence, field by field.","uniqueKey":"suite.oneOf.0.comparison.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite.oneOf.0.comparison","typeLabel":"ComparisonConfig · object | null"}},"title":"ReconciliationSuite","required":["name"],"additionalProperties":false,"description":"The suite from the yaml input. It is not set when the request gives the\n suite as a proto, or when the YAML text does not give a suite.","uniqueKey":"suite.oneOf.0","typeLabel":"ReconciliationSuite · object"},{"type":"null","properties":{"name":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9_-]*$","description":"Short machine identifier for the suite.\n Unique machine identifier for the suite, used as the stable key for tracking runs over time.\n Alphanumerics, hyphens, and underscores. May be a UUID."},"title":{"oneOf":[{"type":"string","description":"Human-readable title for the suite.\n Displayed in dashboards and reports. Defaults to name when not set."},{"type":"null","description":"Human-readable title for the suite.\n Displayed in dashboards and reports. Defaults to name when not set."}]},"description":{"oneOf":[{"type":"string","description":"Optional longer description of the suite's purpose."},{"type":"null","description":"Optional longer description of the suite's purpose."}]},"reconciliations":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9_-]*$","description":"Unique machine identifier within the suite. Alphanumerics, hyphens, and underscores. May be a UUID."},"title":{"oneOf":[{"type":"string","description":"Human-readable title. Displayed in reports. Defaults to name when not set."},{"type":"null","description":"Human-readable title. Displayed in reports. Defaults to name when not set."}]},"description":{"oneOf":[{"type":"string","description":"Optional longer description explaining what this reconciliation validates."},{"type":"null","description":"Optional longer description explaining what this reconciliation validates."}]},"source":{"oneOf":[{"type":"object","title":"Dataset","description":"Source dataset to compare from — the \"expected\" or \"authoritative\" side.","required":["connection","query"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map."},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel."},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel."}]},"columns":{"type":"array","items":{"type":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns."},"excludeColumns":{"type":"array","items":{"type":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns."},"query":{"type":"string","title":"query","description":"Raw SQL query returning the dataset.\n Should be a SELECT or WITH (CTE) statement.\n Supports template variable interpolation via {{variable_name}} syntax."}},"additionalProperties":false},{"type":"object","title":"Dataset","description":"Source dataset to compare from — the \"expected\" or \"authoritative\" side.","required":["connection","table"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map."},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel."},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel."}]},"columns":{"type":"array","items":{"type":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns."},"excludeColumns":{"type":"array","items":{"type":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns."},"table":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Table or view name (e.g., \"orders\", \"fact_sales\").\n Required — this is the actual object name."},"columns":{"type":"array","items":{"type":"string"},"description":"Explicit list of columns to include in the comparison.\n When set, only these columns are selected from the table.\n Mutually exclusive with exclude_columns."},"excludeColumns":{"type":"array","items":{"type":"string"},"description":"Columns to exclude from the comparison.\n All columns except these are selected (resolved at runtime via table metadata).\n Useful for skipping volatile columns (e.g., updated_at, etl_batch_id).\n Mutually exclusive with columns."},"database":{"oneOf":[{"type":"string","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog."},{"type":"null","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog."}]},"schema":{"oneOf":[{"type":"string","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema."},{"type":"null","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema."}]},"where":{"oneOf":[{"type":"string","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\""},{"type":"null","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\""}]}},"title":"table","required":["name"],"additionalProperties":false,"description":"Table reference with optional column selection.\n Automatically generates a SELECT query from the table metadata."}},"additionalProperties":false}]},"target":{"oneOf":[{"type":"object","title":"Dataset","description":"Target dataset to compare against — the \"actual\" or \"replicated\" side.","required":["connection","query"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map."},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel."},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel."}]},"columns":{"type":"array","items":{"type":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns."},"excludeColumns":{"type":"array","items":{"type":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns."},"query":{"type":"string","title":"query","description":"Raw SQL query returning the dataset.\n Should be a SELECT or WITH (CTE) statement.\n Supports template variable interpolation via {{variable_name}} syntax."}},"additionalProperties":false},{"type":"object","title":"Dataset","description":"Target dataset to compare against — the \"actual\" or \"replicated\" side.","required":["connection","table"],"properties":{"connection":{"type":"string","title":"connection","minLength":1,"description":"Name of the connection to use. Must reference a connection configured\n in the runner's connection map."},"asOf":{"oneOf":[{"type":"string","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel."},{"type":"null","title":"as_of","description":"Time-travel timestamp for snapshot queries (e.g., \"2026-02-01 00:00:00\").\n When set, wraps the query with database-specific time-travel syntax:\n - Snowflake: AT(TIMESTAMP => '\u003cas_of>')\n - BigQuery: FOR SYSTEM_TIME AS OF TIMESTAMP '\u003cas_of>'\n - Databricks: TIMESTAMP AS OF '\u003cas_of>'\n Has no effect on databases that don't support time-travel."}]},"columns":{"type":"array","items":{"type":"string"},"title":"columns","description":"Columns of the query's result to compare. When set, only these columns\n are read from the query; the rest of its SELECT list is ignored.\n Only with query — a table takes its columns inside table.\n Mutually exclusive with exclude_columns."},"excludeColumns":{"type":"array","items":{"type":"string"},"title":"exclude_columns","description":"Columns of the query's result to leave out of the comparison. Every other\n column is read (resolved at runtime from the query's result shape).\n Only with query — a table takes its exclusions inside table.\n Mutually exclusive with columns."},"table":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Table or view name (e.g., \"orders\", \"fact_sales\").\n Required — this is the actual object name."},"columns":{"type":"array","items":{"type":"string"},"description":"Explicit list of columns to include in the comparison.\n When set, only these columns are selected from the table.\n Mutually exclusive with exclude_columns."},"excludeColumns":{"type":"array","items":{"type":"string"},"description":"Columns to exclude from the comparison.\n All columns except these are selected (resolved at runtime via table metadata).\n Useful for skipping volatile columns (e.g., updated_at, etl_batch_id).\n Mutually exclusive with columns."},"database":{"oneOf":[{"type":"string","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog."},{"type":"null","description":"Database/catalog name (e.g., \"PROD_RAW\", \"my_project\").\n Maps to: Snowflake database, BigQuery project, Databricks catalog."}]},"schema":{"oneOf":[{"type":"string","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema."},{"type":"null","description":"Schema/dataset name (e.g., \"public\", \"analytics\").\n Maps to: Snowflake schema, BigQuery dataset, Databricks schema."}]},"where":{"oneOf":[{"type":"string","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\""},{"type":"null","description":"Row filter — appended as WHERE clause to the generated SELECT.\n Example: \"created_at >= '2024-01-01' AND status = 'active'\""}]}},"title":"table","required":["name"],"additionalProperties":false,"description":"Table reference with optional column selection.\n Automatically generates a SELECT query from the table metadata."}},"additionalProperties":false}]},"keyColumn":{"oneOf":[{"type":"string","description":"Deprecated: use key_columns instead. Single primary key column used for\n ordering and segmentation during bisection. Retained for backward\n compatibility — existing single-key configs and stored audit logs keep\n working. When key_columns is set, this field is ignored. Readers should\n resolve the effective key via key_columns first, falling back to this.","deprecated":true},{"type":"null","description":"Deprecated: use key_columns instead. Single primary key column used for\n ordering and segmentation during bisection. Retained for backward\n compatibility — existing single-key configs and stored audit logs keep\n working. When key_columns is set, this field is ignored. Readers should\n resolve the effective key via key_columns first, falling back to this.","deprecated":true}]},"keyColumns":{"type":"array","items":{"type":"string"},"description":"Ordered list of key columns used for ordering and segmentation during\n bisection. Supports composite (multi-column) keys; the bisection orders and\n range-filters on the column tuple so the engine can prune via a matching\n primary key / index. A single-element list is equivalent to setting\n key_column. Required for ROW_CHECKSUM and ROW_COUNT modes (this or the\n deprecated key_column). Optional in AGGREGATE mode, where it only stands in\n for group_columns when those are unset."},"mode":{"type":"string","title":"ReconciliationMode","enum":["RECONCILIATION_MODE_UNSPECIFIED","RECONCILIATION_MODE_ROW_COUNT","RECONCILIATION_MODE_ROW_CHECKSUM","RECONCILIATION_MODE_AGGREGATE"],"description":"Comparison mode controlling how source and target are compared.","not":{"enum":[0]}},"hashAlgorithm":{"oneOf":[{"type":"string","title":"HashAlgorithm","enum":["HASH_ALGORITHM_UNSPECIFIED","HASH_ALGORITHM_MD5","HASH_ALGORITHM_FARM_FINGERPRINT","HASH_ALGORITHM_XXHASH64"],"description":"Hash algorithm for row checksums in ROW_CHECKSUM mode.\n When unset, auto-negotiates the best common algorithm between the\n source and target database dialects."},{"type":"null","title":"HashAlgorithm","enum":["HASH_ALGORITHM_UNSPECIFIED","HASH_ALGORITHM_MD5","HASH_ALGORITHM_FARM_FINGERPRINT","HASH_ALGORITHM_XXHASH64"],"description":"Hash algorithm for row checksums in ROW_CHECKSUM mode.\n When unset, auto-negotiates the best common algorithm between the\n source and target database dialects."}]},"columnMapping":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string","minLength":1,"description":"Column name in the source dataset."},"target":{"type":"string","minLength":1,"description":"Corresponding column name in the target dataset."}},"title":"ColumnMapping","required":["source","target"],"additionalProperties":false,"description":"ColumnMapping maps a source column name to a target column name.\n Used when source and target use different naming conventions for the same data\n (e.g., snake_case vs SCREAMING_SNAKE_CASE, or completely different names).\n Only columns with different names need explicit mapping — columns with\n identical names (or case-insensitive matches when case_insensitive is true)\n are matched automatically."},"description":"Explicit column name mapping between source and target.\n Only columns with different names need mapping — identical names\n (or case-insensitive matches) are matched automatically."},"caseInsensitive":{"oneOf":[{"type":"boolean","description":"When true, automatically matches columns differing only in letter case\n (e.g., user_id matches USER_ID). Defaults to true when not set.\n Set to false to require exact case matching."},{"type":"null","description":"When true, automatically matches columns differing only in letter case\n (e.g., user_id matches USER_ID). Defaults to true when not set.\n Set to false to require exact case matching."}]},"bisection":{"oneOf":[{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether bisection drill-down is enabled.\n When false, only the quick-check (count + checksum) runs — mismatches\n are detected but not localized to specific rows."},"factor":{"oneOf":[{"type":"integer","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64."},{"type":"null","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64."}]},"threshold":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows."},{"type":"null","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows."}]},"strategy":{"type":"string","title":"SegmentationStrategy","enum":["SEGMENTATION_STRATEGY_UNSPECIFIED","SEGMENTATION_STRATEGY_QUANTILE","SEGMENTATION_STRATEGY_HASH","SEGMENTATION_STRATEGY_TIME"],"description":"Segmentation strategy for splitting key ranges."},"timeColumn":{"oneOf":[{"type":"string","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset."},{"type":"null","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset."}]},"timeGranularity":{"type":"string","title":"TimeGranularity","enum":["TIME_GRANULARITY_UNSPECIFIED","TIME_GRANULARITY_HOUR","TIME_GRANULARITY_DAY","TIME_GRANULARITY_WEEK","TIME_GRANULARITY_MONTH","TIME_GRANULARITY_QUARTER","TIME_GRANULARITY_YEAR"],"description":"Granularity for time-based segmentation. Default: DAY.\n Controls the width of each time bucket when strategy is TIME."}},"title":"BisectionConfig","additionalProperties":false,"description":"Bisection drill-down configuration for ROW_CHECKSUM mode.\n Controls how the key range is recursively split to locate mismatches.\n When not set, uses sensible defaults (factor=32, threshold=16384)."},{"type":"null","properties":{"enabled":{"type":"boolean","description":"Whether bisection drill-down is enabled.\n When false, only the quick-check (count + checksum) runs — mismatches\n are detected but not localized to specific rows."},"factor":{"oneOf":[{"type":"integer","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64."},{"type":"null","maximum":1024,"minimum":2,"format":"int32","description":"Branching factor: how many segments each level is split into.\n Higher values find mismatches faster (fewer levels) but issue more queries per level.\n Default: 32. Typical range: 4–64."}]},"threshold":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows."},{"type":"null","minimum":1,"format":"int32","description":"Row count threshold: stop bisecting when a segment has fewer rows than this.\n Lower values find more precise mismatch locations but issue more queries.\n Default: 16384. Set to 1 to drill down to individual rows."}]},"strategy":{"type":"string","title":"SegmentationStrategy","enum":["SEGMENTATION_STRATEGY_UNSPECIFIED","SEGMENTATION_STRATEGY_QUANTILE","SEGMENTATION_STRATEGY_HASH","SEGMENTATION_STRATEGY_TIME"],"description":"Segmentation strategy for splitting key ranges."},"timeColumn":{"oneOf":[{"type":"string","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset."},{"type":"null","description":"Column for time-based partitioning. Required when strategy is TIME.\n Must be a timestamp, date, or datetime column in the dataset."}]},"timeGranularity":{"type":"string","title":"TimeGranularity","enum":["TIME_GRANULARITY_UNSPECIFIED","TIME_GRANULARITY_HOUR","TIME_GRANULARITY_DAY","TIME_GRANULARITY_WEEK","TIME_GRANULARITY_MONTH","TIME_GRANULARITY_QUARTER","TIME_GRANULARITY_YEAR"],"description":"Granularity for time-based segmentation. Default: DAY.\n Controls the width of each time bucket when strategy is TIME."}},"title":"BisectionConfig","additionalProperties":false,"description":"Bisection drill-down configuration for ROW_CHECKSUM mode.\n Controls how the key range is recursively split to locate mismatches.\n When not set, uses sensible defaults (factor=32, threshold=16384)."}]},"reporting":{"oneOf":[{"type":"object","properties":{"level":{"type":"string","title":"MismatchDetailLevel","enum":["MISMATCH_DETAIL_LEVEL_UNSPECIFIED","MISMATCH_DETAIL_LEVEL_COUNT_ONLY","MISMATCH_DETAIL_LEVEL_WITH_KEYS","MISMATCH_DETAIL_LEVEL_DETAILED"],"description":"Output detail level for mismatched rows."},"sampleLimit":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included."},{"type":"null","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included."}]},"consentAcknowledged":{"type":"boolean","description":"Explicit acknowledgment that detailed row data may be included in the audit log.\n Required when level is DETAILED to prevent accidental exposure of sensitive data.\n The caller must set this to true to confirm they understand the privacy implications."}},"title":"ReportingConfig","additionalProperties":false,"description":"Reporting output configuration controlling how much detail is included\n in the audit log for mismatched rows."},{"type":"null","properties":{"level":{"type":"string","title":"MismatchDetailLevel","enum":["MISMATCH_DETAIL_LEVEL_UNSPECIFIED","MISMATCH_DETAIL_LEVEL_COUNT_ONLY","MISMATCH_DETAIL_LEVEL_WITH_KEYS","MISMATCH_DETAIL_LEVEL_DETAILED"],"description":"Output detail level for mismatched rows."},"sampleLimit":{"oneOf":[{"type":"integer","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included."},{"type":"null","minimum":1,"format":"int32","description":"Maximum number of sample rows to include in output per mismatch segment.\n Limits the size of the audit log when there are many mismatches.\n When not set, all mismatched rows within the reporting level are included."}]},"consentAcknowledged":{"type":"boolean","description":"Explicit acknowledgment that detailed row data may be included in the audit log.\n Required when level is DETAILED to prevent accidental exposure of sensitive data.\n The caller must set this to true to confirm they understand the privacy implications."}},"title":"ReportingConfig","additionalProperties":false,"description":"Reporting output configuration controlling how much detail is included\n in the audit log for mismatched rows."}]},"aggregate":{"oneOf":[{"type":"object","properties":{"measures":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name to aggregate. Must exist in both source and target datasets\n (after column mapping is applied)."},"functions":{"type":"array","items":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"AggregateFunction defines the supported SQL aggregate functions\n for measure comparisons in aggregate reconciliation mode."},"minItems":1,"description":"Aggregate functions to apply to this column.\n Multiple functions produce multiple measure comparisons from one column."}},"title":"Measure","required":["column"],"additionalProperties":false,"description":"Measure defines a column and aggregate function(s) to compare\n between source and target datasets.\n A single measure with multiple functions expands into multiple comparisons\n (e.g., column=\"amount\" functions=[SUM, AVG] produces \"SUM(amount)\" and \"AVG(amount)\")."},"minItems":1,"description":"Measures to compare between source and target.\n Each measure defines a column and one or more aggregate functions to apply."},"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures."},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures."}]},"groupColumns":{"type":"array","items":{"type":"string"},"description":"Columns defining the drill-down hierarchy for aggregate comparison.\n Falls back to the key columns if not set. With no key columns either, the\n whole dataset is compared as a single group, with no GROUP BY.\n\n Single column: flat GROUP BY comparison.\n group_columns: [\"region\"]\n → GROUP BY region\n\n Multiple columns: cumulative GROUP BY drill-down, pruning matched groups\n at each level to focus on divergent branches.\n group_columns: [\"region\", \"city\", \"store\"]\n → Level 0: GROUP BY region\n → Level 1: GROUP BY region, city (only for mismatched regions)\n → Level 2: GROUP BY region, city, store (only for mismatched cities)"}},"title":"AggregateConfig","additionalProperties":false,"description":"Aggregate comparison settings. Required when mode is AGGREGATE.\n Defines which measures to compare and tolerance thresholds."},{"type":"null","properties":{"measures":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name to aggregate. Must exist in both source and target datasets\n (after column mapping is applied)."},"functions":{"type":"array","items":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"AggregateFunction defines the supported SQL aggregate functions\n for measure comparisons in aggregate reconciliation mode."},"minItems":1,"description":"Aggregate functions to apply to this column.\n Multiple functions produce multiple measure comparisons from one column."}},"title":"Measure","required":["column"],"additionalProperties":false,"description":"Measure defines a column and aggregate function(s) to compare\n between source and target datasets.\n A single measure with multiple functions expands into multiple comparisons\n (e.g., column=\"amount\" functions=[SUM, AVG] produces \"SUM(amount)\" and \"AVG(amount)\")."},"minItems":1,"description":"Measures to compare between source and target.\n Each measure defines a column and one or more aggregate functions to apply."},"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures."},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance thresholds for aggregate comparisons.\n When not set, exact match is required for all measures."}]},"groupColumns":{"type":"array","items":{"type":"string"},"description":"Columns defining the drill-down hierarchy for aggregate comparison.\n Falls back to the key columns if not set. With no key columns either, the\n whole dataset is compared as a single group, with no GROUP BY.\n\n Single column: flat GROUP BY comparison.\n group_columns: [\"region\"]\n → GROUP BY region\n\n Multiple columns: cumulative GROUP BY drill-down, pruning matched groups\n at each level to focus on divergent branches.\n group_columns: [\"region\", \"city\", \"store\"]\n → Level 0: GROUP BY region\n → Level 1: GROUP BY region, city (only for mismatched regions)\n → Level 2: GROUP BY region, city, store (only for mismatched cities)"}},"title":"AggregateConfig","additionalProperties":false,"description":"Aggregate comparison settings. Required when mode is AGGREGATE.\n Defines which measures to compare and tolerance thresholds."}]},"errorHandling":{"oneOf":[{"type":"object","properties":{"queryTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit."},{"type":"null","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit."}]},"maxRetries":{"oneOf":[{"type":"integer","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2."},{"type":"null","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2."}]},"retryInitialDelay":{"oneOf":[{"type":"string","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s."},{"type":"null","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s."}]},"retryBackoffFactor":{"oneOf":[{"type":"number","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0."},{"type":"null","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0."}]}},"title":"ErrorHandlingConfig","additionalProperties":false,"description":"Error handling and retry configuration for database queries.\n Controls timeouts and retry behavior for transient failures."},{"type":"null","properties":{"queryTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit."},{"type":"null","format":"duration","description":"Per-query timeout. When a query exceeds this duration, it is cancelled\n and fails with a timeout error. It is not retried, since a query that took\n this long will usually take it again. Covers setup and teardown statements\n too. To bound the whole reconciliation rather than each query, use its\n timeout or the suite's execution.reconciliation_timeout.\n Default: no per-query limit."}]},"maxRetries":{"oneOf":[{"type":"integer","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2."},{"type":"null","maximum":10,"minimum":0,"format":"int32","description":"Maximum retry attempts for transient query failures. Setup and teardown\n statements are never retried, since they need not be safe to run twice.\n The total number of attempts is max_retries + 1 (initial + retries).\n Default: 2."}]},"retryInitialDelay":{"oneOf":[{"type":"string","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s."},{"type":"null","format":"duration","description":"Initial backoff delay before the first retry.\n Subsequent retries multiply this by retry_backoff_factor.\n Default: 1s."}]},"retryBackoffFactor":{"oneOf":[{"type":"number","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0."},{"type":"null","minimum":1,"format":"double","description":"Backoff multiplier applied after each retry.\n Delay for attempt N = retry_initial_delay * retry_backoff_factor^(N-1).\n Must be >= 1.0 to ensure delays don't decrease.\n Default: 2.0."}]}},"title":"ErrorHandlingConfig","additionalProperties":false,"description":"Error handling and retry configuration for database queries.\n Controls timeouts and retry behavior for transient failures."}]},"window":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause."},{"type":"null","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause."}]},"lookback":{"type":"string","format":"duration","description":"How far back to look from the current time.\n Defines the window as [now - lookback, now].\n Examples: \"336h\" (14 days), \"2h\", \"720h\" (30 days)."},"strategy":{"type":"string","title":"WindowStrategy","enum":["WINDOW_STRATEGY_UNSPECIFIED","WINDOW_STRATEGY_SLIDING","WINDOW_STRATEGY_FIXED"],"description":"Windowing strategy controlling how boundaries are computed."}},"title":"WindowConfig","required":["lookback"],"additionalProperties":false,"description":"Time window for incremental comparison.\n When set, automatically provides a {{window_start}} template variable\n for filtering queries to a recent time range."},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause."},{"type":"null","description":"Column being windowed.\n Informational metadata for the audit trail — the actual filtering is done\n via the {{window_start}} variable in your query WHERE clause."}]},"lookback":{"type":"string","format":"duration","description":"How far back to look from the current time.\n Defines the window as [now - lookback, now].\n Examples: \"336h\" (14 days), \"2h\", \"720h\" (30 days)."},"strategy":{"type":"string","title":"WindowStrategy","enum":["WINDOW_STRATEGY_UNSPECIFIED","WINDOW_STRATEGY_SLIDING","WINDOW_STRATEGY_FIXED"],"description":"Windowing strategy controlling how boundaries are computed."}},"title":"WindowConfig","required":["lookback"],"additionalProperties":false,"description":"Time window for incremental comparison.\n When set, automatically provides a {{window_start}} template variable\n for filtering queries to a recent time range."}]},"setup":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map."},"queries":{"type":"array","items":{"type":"string","minItems":1},"minItems":1,"description":"SQL queries to execute in order on this connection."}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level."},"description":"Setup queries run before this specific reconciliation.\n Executes after suite-level setup but before data comparison."},"teardown":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map."},"queries":{"type":"array","items":{"type":"string","minItems":1},"minItems":1,"description":"SQL queries to execute in order on this connection."}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level."},"description":"Teardown queries run after this specific reconciliation completes."},"teardownOnFailure":{"oneOf":[{"type":"boolean","description":"Whether teardown runs on failure for this reconciliation.\n When not set, inherits from suite-level teardown_on_failure."},{"type":"null","description":"Whether teardown runs on failure for this reconciliation.\n When not set, inherits from suite-level teardown_on_failure."}]},"ignoreSetupErrors":{"oneOf":[{"type":"boolean","description":"When true, logs setup errors as warnings and continues.\n When not set, inherits from suite-level ignore_setup_errors."},{"type":"null","description":"When true, logs setup errors as warnings and continues.\n When not set, inherits from suite-level ignore_setup_errors."}]},"cutoff":{"oneOf":[{"type":"object","properties":{"source":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only."},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only."}]},"target":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only."},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only."}]},"combine":{"type":"string","title":"CutoffCombineStrategy","enum":["CUTOFF_COMBINE_STRATEGY_UNSPECIFIED","CUTOFF_COMBINE_STRATEGY_MIN","CUTOFF_COMBINE_STRATEGY_MAX","CUTOFF_COMBINE_STRATEGY_SOURCE","CUTOFF_COMBINE_STRATEGY_TARGET"],"description":"How to combine watermarks when both sides are configured.\n Default: MIN (use the smaller watermark for safety).\n Ignored when only one side has a watermark."},"truncate":{"type":"string","title":"CutoffTruncateUnit","enum":["CUTOFF_TRUNCATE_UNIT_UNSPECIFIED","CUTOFF_TRUNCATE_UNIT_HOUR","CUTOFF_TRUNCATE_UNIT_DAY","CUTOFF_TRUNCATE_UNIT_WEEK","CUTOFF_TRUNCATE_UNIT_MONTH","CUTOFF_TRUNCATE_UNIT_QUARTER","CUTOFF_TRUNCATE_UNIT_YEAR"],"description":"Truncate the combined watermark to a time boundary.\n Example: HOUR truncates 08:47:12 to 08:00:00.\n Applied after combining, before offset."},"offset":{"oneOf":[{"type":"string","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier."},{"type":"null","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier."}]},"applySource":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator."},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator."}]},"applyTarget":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator."},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator."}]}},"title":"CutoffConfig","additionalProperties":false,"description":"Dynamic cutoff filter for sync reconciliation.\n Derives a watermark from actual data to exclude rows not yet synced.\n Applied as WHERE filter to both source and target queries at runtime."},{"type":"null","properties":{"source":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only."},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for source.\n When not set, derives from target only."}]},"target":{"oneOf":[{"type":"object","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only."},{"type":"null","properties":{"column":{"type":"string","description":"Column to derive the watermark from (e.g., \"created_at\", \"synced_at\").\n Required when query is not set."},"aggregate":{"type":"string","title":"CutoffAggregateFunction","enum":["CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","CUTOFF_AGGREGATE_FUNCTION_MAX","CUTOFF_AGGREGATE_FUNCTION_MIN"],"description":"Aggregate function to derive the watermark. Default: MAX.\n Only used when query is not set."},"query":{"oneOf":[{"type":"string","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."},{"type":"null","description":"Custom SQL query for watermark derivation.\n Must return a single row with a \"watermark\" column.\n When not set, auto-generated from the dataset at runtime.\n After resolution, this field is populated with the actual query that was executed."}]}},"title":"CutoffSideConfig","additionalProperties":false,"description":"Per-side watermark derivation config for target.\n When not set, derives from source only."}]},"combine":{"type":"string","title":"CutoffCombineStrategy","enum":["CUTOFF_COMBINE_STRATEGY_UNSPECIFIED","CUTOFF_COMBINE_STRATEGY_MIN","CUTOFF_COMBINE_STRATEGY_MAX","CUTOFF_COMBINE_STRATEGY_SOURCE","CUTOFF_COMBINE_STRATEGY_TARGET"],"description":"How to combine watermarks when both sides are configured.\n Default: MIN (use the smaller watermark for safety).\n Ignored when only one side has a watermark."},"truncate":{"type":"string","title":"CutoffTruncateUnit","enum":["CUTOFF_TRUNCATE_UNIT_UNSPECIFIED","CUTOFF_TRUNCATE_UNIT_HOUR","CUTOFF_TRUNCATE_UNIT_DAY","CUTOFF_TRUNCATE_UNIT_WEEK","CUTOFF_TRUNCATE_UNIT_MONTH","CUTOFF_TRUNCATE_UNIT_QUARTER","CUTOFF_TRUNCATE_UNIT_YEAR"],"description":"Truncate the combined watermark to a time boundary.\n Example: HOUR truncates 08:47:12 to 08:00:00.\n Applied after combining, before offset."},"offset":{"oneOf":[{"type":"string","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier."},{"type":"null","format":"duration","description":"Time offset applied after truncation.\n Negative durations subtract from the cutoff (safety buffer).\n Example: \"-30m\" shifts the cutoff 30 minutes earlier."}]},"applySource":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator."},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the source side.\n When not set, uses the source derivation column with \u003c= operator."}]},"applyTarget":{"oneOf":[{"type":"object","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator."},{"type":"null","properties":{"column":{"oneOf":[{"type":"string","description":"Column to filter on. When not set, uses the derivation column from that side."},{"type":"null","description":"Column to filter on. When not set, uses the derivation column from that side."}]},"operator":{"oneOf":[{"type":"string","description":"Comparison operator. Default: \"\u003c=\"."},{"type":"null","description":"Comparison operator. Default: \"\u003c=\"."}]}},"title":"CutoffApplyConfig","additionalProperties":false,"description":"How to apply the cutoff as a WHERE filter on the target side.\n When not set, uses the target derivation column with \u003c= operator."}]}},"title":"CutoffConfig","additionalProperties":false,"description":"Dynamic cutoff filter for sync reconciliation.\n Derives a watermark from actual data to exclude rows not yet synced.\n Applied as WHERE filter to both source and target queries at runtime."}]},"annotations":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"minLength":1,"description":"String key for the annotation."},"values":{"type":"array","items":{"type":"string","maxLength":100,"minLength":1,"maxItems":20},"maxItems":20,"description":"Optional list of values that the annotation can carry.\n\n A value is something entities are filtered and searched by, not free-form\n metadata, so keep it to a label a person would pick out of a list. The limit\n is set to hold an identifier or a link the annotated system generated —\n truncating one of those produces a value that no longer resolves, and no\n longer matches the filter it exists for. Put prose in the entity\n description instead."}},"title":"Annotation","required":["name"],"additionalProperties":false,"description":"Annotations can be used to annotate any entity with a key:value pair.\n These annotations can be used for filtering and searching entities."},"description":"Case-level annotations. Merged with suite-level annotations and\n deployment-level annotations at promote time, then exposed on the\n case asset (PromotedReconCaseMetadata)."},"timeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for this reconciliation: its setup, quick check\n and any drill. Overrides the suite's execution.reconciliation_timeout.\n A reconciliation that exceeds it is recorded as failed with a timeout\n error and the run moves on to the next one. It never extends the run's\n own timeout. For a bound on each individual query, use\n error_handling.query_timeout.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"},{"type":"null","format":"duration","description":"Maximum wall-clock time for this reconciliation: its setup, quick check\n and any drill. Overrides the suite's execution.reconciliation_timeout.\n A reconciliation that exceeds it is recorded as failed with a timeout\n error and the run moves on to the next one. It never extends the run's\n own timeout. For a bound on each individual query, use\n error_handling.query_timeout.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"}]},"rowCount":{"oneOf":[{"type":"object","properties":{"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal."},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal."}]}},"title":"RowCountConfig","additionalProperties":false,"description":"Row count comparison settings. Only used when mode is ROW_COUNT.\n Sets the tolerance a difference in row counts may stay within."},{"type":"null","properties":{"thresholds":{"oneOf":[{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal."},{"type":"null","properties":{"absolute":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences."}]},"percentage":{"oneOf":[{"type":"number","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."},{"type":"null","minimum":0,"format":"double","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance."}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity."}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}},"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\")."},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only."}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"Tolerance for the difference between the source and target row counts.\n A difference within it reports MISMATCHED_WITHIN_THRESHOLD instead of\n MISMATCHED, and no drill runs for it. Same semantics as aggregate\n thresholds, applied to COUNT(*): a difference is accepted when it is within\n absolute or within percentage, computed against percentage_basis.\n When not set, the counts must be equal."}]}},"title":"RowCountConfig","additionalProperties":false,"description":"Row count comparison settings. Only used when mode is ROW_COUNT.\n Sets the tolerance a difference in row counts may stay within."}]},"comparison":{"oneOf":[{"type":"object","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair."},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."}]}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column."},"description":"Settings for individual columns, overriding the settings above."},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."}]}},"title":"ComparisonConfig","additionalProperties":false,"description":"How column values are compared in ROW_CHECKSUM mode. Overrides the suite's\n comparison settings. When not set, the suite's apply, and without those\n every column is compared at the precision its types on both sides allow."},{"type":"null","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair."},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."}]}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column."},"description":"Settings for individual columns, overriding the settings above."},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."}]}},"title":"ComparisonConfig","additionalProperties":false,"description":"How column values are compared in ROW_CHECKSUM mode. Overrides the suite's\n comparison settings. When not set, the suite's apply, and without those\n every column is compared at the precision its types on both sides allow."}]}},"title":"Reconciliation","required":["name","source","target"],"additionalProperties":false,"description":"Reconciliation defines a single reconciliation scenario comparing data\n between a source and target dataset. Each reconciliation runs independently\n and produces its own pass/mismatch/fail result.\naggregate_config_required // aggregate config is required when mode is AGGREGATE\nkey_column_and_key_columns_mutually_exclusive // set either key_column (single) or key_columns (composite), not both\nkey_column_required_for_non_aggregate // key_column or key_columns is required unless mode is AGGREGATE\n"},"minItems":1,"description":"Reconciliation scenarios to execute.\n Each reconciliation compares data between a source and target dataset."},"setup":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map."},"queries":{"type":"array","items":{"type":"string","minItems":1},"minItems":1,"description":"SQL queries to execute in order on this connection."}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level."},"description":"Setup queries run once before all reconciliations begin.\n Use for creating temp tables, loading fixtures, or preparing the environment.\n Queries execute in order; all connections run sequentially."},"teardown":{"type":"array","items":{"type":"object","properties":{"connection":{"type":"string","minLength":1,"description":"Connection name to execute these queries on.\n Must reference a connection configured in the runner's connection map."},"queries":{"type":"array","items":{"type":"string","minItems":1},"minItems":1,"description":"SQL queries to execute in order on this connection."}},"title":"ConnectionQueries","required":["connection"],"additionalProperties":false,"description":"ConnectionQueries associates SQL queries with a specific connection.\n Used for setup and teardown blocks at both suite and reconciliation level."},"description":"Teardown queries run once after all reconciliations complete.\n Use for cleaning up temp tables or restoring state."},"teardownOnFailure":{"type":"boolean","description":"Whether teardown runs even when reconciliations fail with infrastructure errors.\n When false (default), teardown is skipped on failure to preserve state for debugging."},"ignoreSetupErrors":{"type":"boolean","description":"When true, logs setup query errors as warnings and continues execution\n instead of aborting the run. Useful when setup creates IF NOT EXISTS objects."},"variables":{"type":"object","additionalProperties":{"type":"string","title":"value"},"description":"Template variables for query interpolation via {{variable_name}} syntax.\n Values can be literal strings or template expressions:\n - Literal: \"2026-01-01\"\n - Time expression: \"{{today - 30d}}\", \"{{now - 2h}}\"\n - Built-in: \"{{now}}\", \"{{today}}\", \"{{window_start}}\"\n Variables are resolved once at the start of the run and frozen."},"strictTimeReferences":{"type":"boolean","description":"When true, time reference detection (e.g. NOW(), CURRENT_DATE, GETDATE()\n in queries) returns an error instead of a warning. Prevents non-deterministic\n queries that produce different results on each run."},"annotations":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"minLength":1,"description":"String key for the annotation."},"values":{"type":"array","items":{"type":"string","maxLength":100,"minLength":1,"maxItems":20},"maxItems":20,"description":"Optional list of values that the annotation can carry.\n\n A value is something entities are filtered and searched by, not free-form\n metadata, so keep it to a label a person would pick out of a list. The limit\n is set to hold an identifier or a link the annotated system generated —\n truncating one of those produces a value that no longer resolves, and no\n longer matches the filter it exists for. Put prose in the entity\n description instead."}},"title":"Annotation","required":["name"],"additionalProperties":false,"description":"Annotations can be used to annotate any entity with a key:value pair.\n These annotations can be used for filtering and searching entities."},"description":"Suite-level annotations. Each annotation is a name with zero or more\n string values. Applied to the deployed suite asset and inherited by every\n reconciliation case under the suite. Merged with per-case annotations and\n deployment-level annotations at promote time — the final, deduplicated\n list is exposed on PromotedReconSuiteMetadata / PromotedReconCaseMetadata\n and surfaced to the rest of the SYNQ platform via EntityAnnotations."},"execution":{"oneOf":[{"type":"object","properties":{"timeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"}]},"concurrency":{"oneOf":[{"type":"integer","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum."},{"type":"null","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum."}]},"reconciliationTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"}]}},"title":"ExecutionConfig","additionalProperties":false,"description":"How runs of this suite execute: the wall-clock budget of a run and how\n many reconciliations run at the same time. Read by every run of the\n suite, local or server-side; a run-level override (a CLI flag, the\n execution_timeout on a trigger or on a deployment) takes precedence."},{"type":"null","properties":{"timeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single run of the suite (the quick check\n plus any bisection drill). A run that exceeds it is cancelled and the\n reconciliations still running are reported as failed. Server-side runs\n clamp the value to a supported range.\n\n Precedence, most specific first: the per-run override, the deployment's\n execution_timeout, this field, the runner default.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"}]},"concurrency":{"oneOf":[{"type":"integer","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum."},{"type":"null","maximum":64,"minimum":1,"format":"int32","description":"Maximum number of reconciliations run in parallel. 1 (the default) runs\n them one after another. Each parallel reconciliation issues its own\n queries, so this multiplies the load on the source and target\n warehouses. Server-side runs clamp the value to a supported maximum."}]},"reconciliationTimeout":{"oneOf":[{"type":"string","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"},{"type":"null","format":"duration","description":"Maximum wall-clock time for a single reconciliation of the suite: its\n setup, quick check and any drill. A reconciliation that exceeds it is\n stopped and recorded as failed with a timeout error, and the run moves on\n to the next one, so one slow query cannot use up the whole run's timeout.\n It never extends the run: whichever of the two runs out first applies.\n\n A reconciliation's own timeout takes precedence. Unset means only the\n run's timeout bounds a reconciliation.\nduration.gt = 0s\nduration.gt_lt = 0s\nduration.gt_lt_exclusive = 0s\nduration.gt_lte = 0s\nduration.gt_lte_exclusive = 0s\n"}]}},"title":"ExecutionConfig","additionalProperties":false,"description":"How runs of this suite execute: the wall-clock budget of a run and how\n many reconciliations run at the same time. Read by every run of the\n suite, local or server-side; a run-level override (a CLI flag, the\n execution_timeout on a trigger or on a deployment) takes precedence."}]},"comparison":{"oneOf":[{"type":"object","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair."},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."}]}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column."},"description":"Settings for individual columns, overriding the settings above."},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."}]}},"title":"ComparisonConfig","additionalProperties":false,"description":"Default comparison settings for every reconciliation in the suite. A\n reconciliation's own comparison settings take precedence, field by field."},{"type":"null","properties":{"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places decimal and floating-point columns are compared\n at, or exact. When not set, a decimal column is compared at the scale both\n sides share, and a floating-point column at the digits both sides hold.\n Integer, text, timestamp and other columns are not affected.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name as the source side reports it, matched case-insensitively.\n With a column_mapping, this is the source column of the pair."},"numericScale":{"oneOf":[{"type":"object","title":"exact","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["exact"],"properties":{"exact":{"type":"boolean","title":"exact","description":"Compare at the full precision the column holds. A decimal is compared\n at its declared scale, which must be known and the same on both sides,\n otherwise the reconciliation fails rather than rounding either side. A\n floating-point column is compared digit for digit, which needs both sides\n on the same kind of database: across two different ones the run fails\n with a message instead. Must be true when set.","const":"true"}},"additionalProperties":false},{"type":"object","title":"places","description":"How many decimal places this column is compared at, or exact. Overrides\n the reconciliation's and the suite's numeric_scale.","required":["places"],"properties":{"places":{"type":"integer","title":"places","maximum":18,"minimum":0,"format":"int32","description":"Round both sides to this many decimal places before comparing, whatever\n their types. A value that differs only beyond the last place matches.\n Use it to tolerate a known rounding by a loader, or to compare a\n floating-point column with a decimal one."}},"additionalProperties":false},{"type":"null"}]},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second this timestamp column is compared to. Overrides the\n reconciliation's and the suite's timestamp_precision.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."},{"type":"null","minLength":1,"description":"The time zone the source side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's source_time_zone."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."},{"type":"null","minLength":1,"description":"The time zone the target side holds this column's wall clock in.\n Overrides the reconciliation's and the suite's target_time_zone."}]}},"title":"ColumnComparison","required":["column"],"additionalProperties":false,"description":"ColumnComparison holds the comparison settings of one column."},"description":"Settings for individual columns, overriding the settings above."},"timestampPrecision":{"oneOf":[{"type":"string","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}},{"type":"null","title":"TimestampPrecision","enum":["TIMESTAMP_PRECISION_UNSPECIFIED","TIMESTAMP_PRECISION_SECOND","TIMESTAMP_PRECISION_MILLISECOND","TIMESTAMP_PRECISION_MICROSECOND","TIMESTAMP_PRECISION_EXACT"],"description":"How much of a second timestamp columns are compared to, timestamp key\n columns included. When not set, a timestamp is compared at the precision\n both sides hold, the coarser of the two. Date, numeric, text and other\n columns are not affected.","not":{"enum":[0]}}]},"sourceTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."},{"type":"null","minLength":1,"description":"The time zone the source side's timestamps without a time zone hold their\n wall clock in, as an IANA name such as Europe/Warsaw. When not set, they\n are read as UTC. A timestamp with a time zone already says which instant\n it is and is not affected."}]},"targetTimeZone":{"oneOf":[{"type":"string","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."},{"type":"null","minLength":1,"description":"The time zone the target side's timestamps without a time zone hold their\n wall clock in, as source_time_zone does for the source side."}]}},"title":"ComparisonConfig","additionalProperties":false,"description":"Default comparison settings for every reconciliation in the suite. A\n reconciliation's own comparison settings take precedence, field by field."}]}},"title":"ReconciliationSuite","required":["name"],"additionalProperties":false,"description":"The suite from the yaml input. It is not set when the request gives the\n suite as a proto, or when the YAML text does not give a suite.","uniqueKey":"suite.oneOf.1","typeLabel":"null"}],"uniqueKey":"suite","typeLabel":"ReconciliationSuite · object | null"}},"title":"ValidateSuiteResponse","additionalProperties":false,"uniqueKey":"","typeLabel":"ValidateSuiteResponse · object"},"examples":{"Example":{"title":"Example","value":{"valid":true,"issues":[{"severity":"SUITE_VALIDATION_SEVERITY_UNSPECIFIED","fieldPath":"\u003cstring>","message":"\u003cstring>","position":{"line":123,"column":123}}],"suite":{"name":"\u003cstring>","title":"\u003cstring>","description":"\u003cstring>","reconciliations":[{"name":"\u003cstring>","source":{"connection":"\u003cstring>","query":"\u003cstring>","asOf":"\u003cstring>","columns":["\u003cstring>"],"excludeColumns":["\u003cstring>"]},"target":{"connection":"\u003cstring>","query":"\u003cstring>","asOf":"\u003cstring>","columns":["\u003cstring>"],"excludeColumns":["\u003cstring>"]},"title":"\u003cstring>","description":"\u003cstring>","keyColumn":"\u003cstring>","keyColumns":["\u003cstring>"],"mode":"RECONCILIATION_MODE_UNSPECIFIED","hashAlgorithm":"HASH_ALGORITHM_UNSPECIFIED","columnMapping":[{"source":"\u003cstring>","target":"\u003cstring>"}],"caseInsensitive":true,"bisection":{"enabled":true,"factor":513,"threshold":2,"strategy":"SEGMENTATION_STRATEGY_UNSPECIFIED","timeColumn":"\u003cstring>","timeGranularity":"TIME_GRANULARITY_UNSPECIFIED"},"reporting":{"level":"MISMATCH_DETAIL_LEVEL_UNSPECIFIED","sampleLimit":2,"consentAcknowledged":true},"aggregate":{"measures":[{"column":"\u003cstring>","functions":["AGGREGATE_FUNCTION_UNSPECIFIED"]}],"thresholds":{"absolute":1,"percentage":1,"percentageBasis":"PERCENTAGE_BASIS_UNSPECIFIED","perColumn":[{"column":"\u003cstring>","thresholds":"\u003cunknown>"}],"perMeasure":[{"column":"\u003cstring>","thresholds":"\u003cunknown>","function":"AGGREGATE_FUNCTION_UNSPECIFIED"}]},"groupColumns":["\u003cstring>"]},"errorHandling":{"queryTimeout":"\u003cstring>","maxRetries":5,"retryInitialDelay":"\u003cstring>","retryBackoffFactor":2},"window":{"lookback":"\u003cstring>","column":"\u003cstring>","strategy":"WINDOW_STRATEGY_UNSPECIFIED"},"setup":[{"connection":"\u003cstring>","queries":["\u003cstring>"]}],"teardown":[{"connection":"\u003cstring>","queries":["\u003cstring>"]}],"teardownOnFailure":true,"ignoreSetupErrors":true,"cutoff":{"source":{"column":"\u003cstring>","aggregate":"CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","query":"\u003cstring>"},"target":{"column":"\u003cstring>","aggregate":"CUTOFF_AGGREGATE_FUNCTION_UNSPECIFIED","query":"\u003cstring>"},"combine":"CUTOFF_COMBINE_STRATEGY_UNSPECIFIED","truncate":"CUTOFF_TRUNCATE_UNIT_UNSPECIFIED","offset":"\u003cstring>","applySource":{"column":"\u003cstring>","operator":"\u003cstring>"},"applyTarget":{"column":"\u003cstring>","operator":"\u003cstring>"}},"annotations":[{"name":"\u003cstring>","values":["\u003cstring>"]}],"timeout":"\u003cstring>","rowCount":{"thresholds":{"absolute":1,"percentage":1,"percentageBasis":"PERCENTAGE_BASIS_UNSPECIFIED","perColumn":[{"column":"\u003cstring>","thresholds":"\u003cunknown>"}],"perMeasure":[{"column":"\u003cstring>","thresholds":"\u003cunknown>","function":"AGGREGATE_FUNCTION_UNSPECIFIED"}]}},"comparison":{"numericScale":{"exact":"true"},"columns":[{"column":"\u003cstring>","numericScale":{"exact":"true"},"timestampPrecision":"TIMESTAMP_PRECISION_UNSPECIFIED","sourceTimeZone":"\u003cstring>","targetTimeZone":"\u003cstring>"}],"timestampPrecision":"TIMESTAMP_PRECISION_UNSPECIFIED","sourceTimeZone":"\u003cstring>","targetTimeZone":"\u003cstring>"}}],"setup":[{"connection":"\u003cstring>","queries":["\u003cstring>"]}],"teardown":[{"connection":"\u003cstring>","queries":["\u003cstring>"]}],"teardownOnFailure":true,"ignoreSetupErrors":true,"variables":{},"strictTimeReferences":true,"annotations":[{"name":"\u003cstring>","values":["\u003cstring>"]}],"execution":{"timeout":"\u003cstring>","concurrency":32,"reconciliationTimeout":"\u003cstring>"},"comparison":{"numericScale":{"exact":"true"},"columns":[{"column":"\u003cstring>","numericScale":{"exact":"true"},"timestampPrecision":"TIMESTAMP_PRECISION_UNSPECIFIED","sourceTimeZone":"\u003cstring>","targetTimeZone":"\u003cstring>"}],"timestampPrecision":"TIMESTAMP_PRECISION_UNSPECIFIED","sourceTimeZone":"\u003cstring>","targetTimeZone":"\u003cstring>"}}}}},"exampleType":"generated"}},"exampleType":"generated"}},"security":{"e6e3a4e7-a0de-460f-a4f0-9753c38136eb":{"bearerAuth":{"type":"http","scheme":"bearer","scopes":[],"schemeName":"bearerAuth"}}},"servers":{"48744bfd-8999-4797-84b4-2998e5a947c5":{"url":"https://developer.synq.io"},"75e3b0c9-c49c-4335-af67-cbc071a8c92d":{"url":"https://api.us.synq.io"},"619e14d1-f915-4478-a7e2-ad1b0ade05a7":{"url":"https://api.au.synq.io"}},"schemas":{"0f714d45-a9ef-4cda-ade9-052bf5c9019f":{"type":"object","properties":{"absolute":{"oneOf":[{"type":"number","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences.","format":"double","minimum":0},{"type":"null","description":"Maximum allowed absolute difference per measure.\n When set, differences \u003c= this value are considered within tolerance.\n Example: absolute = 0.01 accepts sub-cent rounding differences.","format":"double","minimum":0}]},"percentage":{"oneOf":[{"type":"number","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance.","format":"double","minimum":0},{"type":"null","description":"Maximum allowed percentage difference per measure.\n Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%.\n The formula used depends on percentage_basis.\n When set, differences \u003c= this percentage are considered within tolerance.","format":"double","minimum":0}]},"percentageBasis":{"type":"string","title":"PercentageBasis","enum":["PERCENTAGE_BASIS_UNSPECIFIED","PERCENTAGE_BASIS_SOURCE","PERCENTAGE_BASIS_TARGET","PERCENTAGE_BASIS_SYMMETRIC"],"description":"Which percentage formula to use for threshold evaluation.\n Only relevant when percentage is set."},"perColumn":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Group column name this override applies to.\n Must match one of the group_columns in the AggregateConfig.","isRequired":true},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this group column level.\n Values here override the parent ThresholdConfig for reconciliation groups\n at this drill-down level. May include per_measure for further specificity.","isRequired":true}},"title":"ColumnThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"ColumnThresholdOverride associates threshold overrides with a specific\n group_column level in the aggregate drill-down hierarchy."},"description":"Per group_column level threshold overrides.\n Allows different tolerance for different levels of the drill-down hierarchy.\n For example, tighter thresholds at the city level than at the region level.\n Entries may themselves contain per_measure overrides for maximum specificity."},"perMeasure":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1,"description":"Column name this override applies to.\n Together with function, forms the measure key (e.g., SUM + \"amount\" = \"SUM(amount)\").","isRequired":true},"thresholds":{"$circularRef":"0f714d45-a9ef-4cda-ade9-052bf5c9019f","description":"Threshold overrides for this specific measure.\n Values here override the parent ThresholdConfig (and any per_column override)\n for this measure only.","isRequired":true},"function":{"type":"string","title":"AggregateFunction","enum":["AGGREGATE_FUNCTION_UNSPECIFIED","AGGREGATE_FUNCTION_SUM","AGGREGATE_FUNCTION_COUNT","AGGREGATE_FUNCTION_AVG","AGGREGATE_FUNCTION_MIN","AGGREGATE_FUNCTION_MAX"],"description":"Aggregate function this override applies to.","not":{"enum":[0]}}},"title":"MeasureThresholdOverride","required":["column","thresholds"],"additionalProperties":false,"description":"MeasureThresholdOverride associates threshold overrides with a specific\n measure (aggregate function + column combination)."},"description":"Per measure threshold overrides.\n Allows different tolerance for different measures within the same reconciliation.\n For example, allow 1% tolerance for SUM(amount) but require exact COUNT match."}},"title":"ThresholdConfig","additionalProperties":false,"description":"ThresholdConfig defines tolerance thresholds for aggregate and row count comparisons.\n A difference is reported as a mismatch only when it exceeds ALL configured\n thresholds (AND logic: both absolute AND percentage must be exceeded).\n\n Thresholds can be overridden at finer granularity:\n - per_column: override thresholds for a specific group_column drill-down level.\n - per_measure: override thresholds for a specific measure (e.g., \"SUM(amount)\").\n - Nesting: per_column entries may contain per_measure overrides (most specific wins).\n\n When no thresholds are configured at any level, exact match is required."}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"http","scheme":"bearer","scopes":[],"schemeName":"bearerAuth"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"Bearer authentication header of the form `Bearer \u003ctoken>`, where `\u003ctoken>` is your auth token.","format":"bearer","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"bearerAuth","name":"Authorization"}],"title":"bearerAuth"}]},"originalFileLocation":"api-reference/openapi.yaml"},"subdomain":"synq-15","siteName":"Coalesce Quality Documentation","title":"ValidateSuite - Coalesce Quality Documentation","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-31T22:22:25.082Z","originalFileLocation":"api-reference/synqagentreconv1yamlservice/validatesuite.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"ValidateSuite checks a suite and gives all the problems that it finds. Each problem has the path of its field. ValidateSuite does not save the suite, so an editor can call it after each change. ValidateSuite does the same checks as synq-recon check-config without --db. It also does the checks that apply only to suites that run in Coalesce Quality. ValidateSuite does not connect to a warehouse. Thus it does not find a query that refers to a table that does not exist. To find these problems, use SuiteConfigService.CheckSuiteInWarehouse. ValidateSuite does not compare the connection names with the integrations of the workspace. A suite gets its integrations when it runs or when you promote it.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Coalesce Quality Documentation\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/synq-15/B7wGMZU-A3ADVMov/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/synq-15/B7wGMZU-A3ADVMov/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/synq-15/B7wGMZU-A3ADVMov/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/synq-15/B7wGMZU-A3ADVMov/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/synq-15/B7wGMZU-A3ADVMov/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/synq-15/B7wGMZU-A3ADVMov/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/synq-15/B7wGMZU-A3ADVMov/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/synq-15/B7wGMZU-A3ADVMov/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/synq-15/B7wGMZU-A3ADVMov/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"ValidateSuite - Coalesce Quality Documentation\">\u003cmeta data-mint-head property=\"og:description\" content=\"ValidateSuite checks a suite and gives all the problems that it finds. Each problem has the path of its field. ValidateSuite does not save the suite, so an editor can call it after each change. ValidateSuite does the same checks as synq-recon check-config without --db. It also does the checks that apply only to suites that run in Coalesce Quality. ValidateSuite does not connect to a warehouse. Thus it does not find a query that refers to a table that does not exist. To find these problems, use SuiteConfigService.CheckSuiteInWarehouse. ValidateSuite does not compare the connection names with the integrations of the workspace. A suite gets its integrations when it runs or when you promote it.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Coalesce Quality Documentation\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://synq-15.mintlify.app/_mintlify/api/og/v2?division=synq.agent.recon.v1.YamlService\u0026amp;title=ValidateSuite\u0026amp;description=ValidateSuite+checks+a+suite+and+gives+all+the+problems+that+it+finds.%0A+Each+problem+has+the+path+of+its+field.+ValidateSuite+does+not+save+the%0A+suite%2C+so+an+ed\u0026amp;theme=c4b0b33f9bac9b90d2a12108\u0026amp;signature=fa47b6ad97b703812a6dcb199ce1eb53cd86b4220c19952b36fc28fc977f1b6a\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"ValidateSuite - Coalesce Quality Documentation\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"ValidateSuite checks a suite and gives all the problems that it finds. Each problem has the path of its field. ValidateSuite does not save the suite, so an editor can call it after each change. ValidateSuite does the same checks as synq-recon check-config without --db. It also does the checks that apply only to suites that run in Coalesce Quality. ValidateSuite does not connect to a warehouse. Thus it does not find a query that refers to a table that does not exist. To find these problems, use SuiteConfigService.CheckSuiteInWarehouse. ValidateSuite does not compare the connection names with the integrations of the workspace. A suite gets its integrations when it runs or when you promote it.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://synq-15.mintlify.app/_mintlify/api/og/v2?division=synq.agent.recon.v1.YamlService\u0026amp;title=ValidateSuite\u0026amp;description=ValidateSuite+checks+a+suite+and+gives+all+the+problems+that+it+finds.%0A+Each+problem+has+the+path+of+its+field.+ValidateSuite+does+not+save+the%0A+suite%2C+so+an+ed\u0026amp;theme=c4b0b33f9bac9b90d2a12108\u0026amp;signature=fa47b6ad97b703812a6dcb199ce1eb53cd86b4220c19952b36fc28fc977f1b6a\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/synq-15/B7wGMZU-A3ADVMov/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Coalesce Quality Documentation\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#135594\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/synqagentreconv1yamlservice/validatesuite.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.synq.io/#organization\",\"name\":\"Coalesce Quality Documentation\",\"url\":\"https://docs.synq.io\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/synq-15/VrNXC6Gv5xCECUGd/logo/coalesce-quality-logo.svg?fit=max\u0026auto=format\u0026n=VrNXC6Gv5xCECUGd\u0026q=85\u0026s=4ad60b616ed815902c710f413d59cf63\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.synq.io#website\",\"name\":\"Coalesce Quality Documentation\",\"url\":\"https://docs.synq.io\",\"publisher\":{\"@id\":\"https://docs.synq.io/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite#webpage\",\"url\":\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite\",\"name\":\"ValidateSuite\",\"description\":\"ValidateSuite checks a suite and gives all the problems that it finds. Each problem has the path of its field. ValidateSuite does not save the suite, so an editor can call it after each change. ValidateSuite does the same checks as synq-recon check-config without --db. It also does the checks that apply only to suites that run in Coalesce Quality. ValidateSuite does not connect to a warehouse. Thus it does not find a query that refers to a table that does not exist. To find these problems, use SuiteConfigService.CheckSuiteInWarehouse. ValidateSuite does not compare the connection names with the integrations of the workspace. A suite gets its integrations when it runs or when you promote it.\",\"dateModified\":\"2026-10-31T22:22:25.082Z\",\"isPartOf\":{\"@id\":\"https://docs.synq.io#website\"},\"breadcrumb\":{\"@id\":\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Developer API\",\"item\":\"https://docs.synq.io/api-reference/getting-started\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"REST API\",\"item\":\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/parseyaml\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"synq.agent.recon.v1.YamlService\",\"item\":\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/parseyaml\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"ValidateSuite\",\"item\":\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite#apireference\",\"headline\":\"ValidateSuite\",\"name\":\"ValidateSuite\",\"description\":\"ValidateSuite checks a suite and gives all the problems that it finds. Each problem has the path of its field. ValidateSuite does not save the suite, so an editor can call it after each change. ValidateSuite does the same checks as synq-recon check-config without --db. It also does the checks that apply only to suites that run in Coalesce Quality. ValidateSuite does not connect to a warehouse. Thus it does not find a query that refers to a table that does not exist. To find these problems, use SuiteConfigService.CheckSuiteInWarehouse. ValidateSuite does not compare the connection names with the integrations of the workspace. A suite gets its integrations when it runs or when you promote it.\",\"url\":\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite\",\"mainEntityOfPage\":{\"@id\":\"https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite#webpage\"},\"dateModified\":\"2026-10-31T22:22:25.082Z\",\"publisher\":{\"@id\":\"https://docs.synq.io/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.synq.io#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Coalesce Quality Documentation\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Coalesce Quality Documentation","nav":{"global":{"anchors":[{"anchor":"Blog","icon":"newspaper","href":"https://coalesce.io/resources/"},{"anchor":"Changelog","icon":"rocket","href":"https://synq.io/changelog"}]},"anchors":[{"anchor":"Documentation","icon":"book-open","groups":[{"group":"Get Started","pages":[{"title":"Introduction","href":"/introduction"},{"title":"Command-line tools","href":"/cli"}]},{"group":"Alerts","pages":[{"title":"Alerts overview","href":"/alerts/alert-overview"},{"title":"Setting up alerts","href":"/alerts/setting-up-alerts"},{"title":"Tagging owners","href":"/alerts/tagging-owners"},{"title":"Routing alerts","href":"/alerts/routing-alerts"},{"title":"Business alerts","href":"/alerts/business-alerts"},{"title":"Writing alert templates","href":"/alerts/templates"}]},{"group":"Monitors","pages":[{"title":"Monitors overview","href":"/monitors/monitors-overview"},{"title":"Setting up monitors","href":"/monitors/setting-up-monitors"},{"title":"Setting up deployment rules","href":"/monitors/deployment-rules"},{"title":"Configuring monitor sensitivity","href":"/monitors/monitor-sensitivity"},{"title":"Monitor feedback","href":"/monitors/monitor-feedback"},{"title":"Muting monitors","href":"/monitors/muting-monitors"},{"title":"Defining monitors in code","href":"/monitors/monitors-as-code"},{"title":"Agent workflow","href":"/monitors/agent-workflow"},{"title":"Monitors CLI reference","href":"/monitors/cli"},{"title":"SQL Tests","href":"/monitors/sql-tests"},{"title":"Working with time dimensions and scheduling for monitors","href":"/monitors/time-dimensions"}]},{"group":"Monitors Types","pages":[{"title":"Table stats monitor","href":"/monitor-types/table-stats-monitor"},{"title":"Volume monitor","href":"/monitor-types/volume-monitor"},{"title":"Freshness monitor","href":"/monitor-types/freshness-monitor"},{"title":"Custom SQL monitor","href":"/monitor-types/custom-sql-monitor"},{"title":"Field stats monitor","href":"/monitor-types/fieldstats"},{"title":"Schema monitor","href":"/monitor-types/schema-monitor"}]},{"group":"Reconciliations","pages":[{"title":"Reconciliation overview","href":"/reconciliation/overview"},{"title":"Getting started","href":"/reconciliation/getting-started"},{"title":"Concepts and vocabulary","href":"/reconciliation/concepts"},{"title":"Authoring suites","href":"/reconciliation/authoring-suites"},{"title":"Comparison modes","href":"/reconciliation/comparison-modes"},{"title":"Time windows and cutoffs","href":"/reconciliation/time-windows-and-cutoffs"},{"title":"Running locally","href":"/reconciliation/running-locally"},{"title":"Workspace suites","href":"/reconciliation/workspace-suites"},{"title":"Investigating results","href":"/reconciliation/investigating-results"},{"title":"CI/CD and automation","href":"/reconciliation/cicd-and-automation"},{"title":"How comparison works","href":"/reconciliation/how-comparison-works"},{"title":"Agent workflow","href":"/reconciliation/agent-workflow"},{"title":"Reconciliation CLI reference","href":"/reconciliation/cli"}]},{"group":"Data Products","pages":[{"title":"Data products overview","href":"/data-products/data-products-overview"},{"title":"Creating a data product","href":"/data-products/creating-a-data-product"},{"title":"BI Status Badge","href":"/data-products/bi-badge"}]},{"group":"Scout AI","pages":[{"title":"Scout overview","href":"/scout/scout"},{"title":"Setting up and configuring Scout","href":"/scout/setting-up-scout"},{"title":"Scout on-premise setup","href":"/scout/on-premise"},{"title":"MCP","href":"/scout/mcp"},{"title":"Agent workflow","href":"/scout/agent-workflow"},{"title":"Scout CLI reference","href":"/scout/cli"}]},{"group":"Ownership","pages":[{"title":"Ownership overview","href":"/ownership/ownership-overview"},{"title":"Creating an owner","href":"/ownership/creating-an-owner"},{"title":"Domains","href":"/ownership/domains"}]},{"group":"Incidents","pages":[{"title":"Incidents overview","href":"/incidents/incident-overview"}]},{"group":"Analytics","pages":[{"title":"Analytics overview","href":"/analytics/analytics-overview"},{"title":"How metrics are calculated","href":"/analytics/how-metrics-are-calculated"},{"title":"Check categories","href":"/analytics/check-categories"}]},{"group":"Query activity","pages":[{"title":"Query activity","href":"/query-activity/overview"}]},{"group":"Lineage","pages":[{"title":"Lineage overview","href":"/lineage/lineage"},{"title":"Column-level lineage","href":"/lineage/column-level-lineage"}]},{"group":"BI Integrations","pages":[{"title":"Looker","href":"/bi-integrations/looker"},{"title":"Tableau","href":"/bi-integrations/tableau"},{"title":"Omni","href":"/bi-integrations/omni"}]},{"group":"Data Warehouse Integrations","pages":[{"title":"BigQuery","href":"/dw-integrations/bigquery"},{"title":"ClickHouse","href":"/dw-integrations/clickhouse"},{"title":"Databricks","href":"/dw-integrations/databricks"},{"title":"Microsoft Fabric","href":"/dw-integrations/fabric"},{"title":"Redshift","href":"/dw-integrations/redshift"},{"title":"Snowflake","href":"/dw-integrations/snowflake"},{"title":"Trino","href":"/dw-integrations/trino"},{"title":"DWH Agent","href":"/dw-integrations/agent"},{"title":"MotherDuck","href":"/dw-integrations/motherduck"}]},{"group":"Transactional databases","pages":[{"title":"Postgres","href":"/transactional-databases/postgres"},{"title":"MySQL","href":"/transactional-databases/mysql"},{"title":"Microsoft SQL Server","href":"/transactional-databases/mssql"},{"title":"Oracle","href":"/transactional-databases/oracle"},{"title":"IBM Db2","href":"/transactional-databases/db2"}]},{"group":"Code Integrations","pages":[{"title":"Code Integration Requirements","href":"/code-integrations/overview"},{"title":"GitHub Integration","href":"/code-integrations/github"},{"title":"GitLab Integration","href":"/code-integrations/gitlab"},{"title":"Bitbucket Integration","href":"/code-integrations/bitbucket"},{"title":"Azure DevOps Integration","href":"/code-integrations/azure-devops"},{"title":"Other Git Providers","href":"/code-integrations/ssh-git"}]},{"group":"dbt Integrations","pages":[{"title":"dbt Core","href":"/dbt-integrations/dbt-core"},{"title":"dbt Cloud","href":"/dbt-integrations/dbt-cloud"},{"title":"Coalesce Quality options for dbt","href":"/dbt-integrations/synq-options"}]},{"group":"SQLMesh Integrations","pages":[{"title":"SQLMesh","href":"/sqlmesh-integrations/sqlmesh"}]},{"group":"Coalesce Integrations","pages":[{"title":"Coalesce Transform","href":"/coalesce-integrations/coalesce-transform"},{"title":"Coalesce Catalog","href":"/coalesce-integrations/coalesce-catalog"}]},{"group":"Orchestration Tool Integrations","pages":[{"title":"Airflow","href":"/orchestration-integrations/airflow"},{"title":"Airflow + dbt Core Linking","href":"/orchestration-integrations/airflow-dbt-core"}]},{"group":"Alerting Integrations","pages":[{"title":"Slack","href":"/alert-integrations/slack"},{"title":"Email","href":"/alert-integrations/email"},{"title":"Microsoft Teams","href":"/alert-integrations/ms-teams"},{"title":"PagerDuty","href":"/alert-integrations/pagerduty"},{"title":"Opsgenie","href":"/alert-integrations/opsgenie"}]},{"group":"Catalogs","pages":[{"title":"Atlan","href":"/catalogs/atlan"}]},{"group":"Google Cloud Integrations","pages":[{"title":"Google Cloud Storage","href":"/gcp-integrations/cloud-storage"},{"title":"Google Cloud Pub/Sub","href":"/gcp-integrations/pubsub"}]},{"group":"Admin","pages":[{"title":"Single Sign-On (SSO)","href":"/admin/sso"},{"title":"Inviting new users","href":"/admin/invite_user"},{"title":"User roles","href":"/admin/user_roles"},{"title":"Monitor Usage","href":"/admin/monitor-usage"}]},{"group":"Security","pages":[{"title":"Security Policy","href":"/security/security"},{"title":"Subprocessors","href":"/security/subprocessors"},{"title":"Data Warehouse Access","href":"/security/dwh-access"},{"title":"Private Connectivity","href":"/security/private-connectivity"},{"title":"IP Whitelist","href":"/security/ip"}]},{"group":"Support","pages":[{"title":"Coalesce Quality Support","href":"/support/support"}]},{"group":"Developer API","pages":[{"title":"Getting Started","href":"/api-reference/getting-started"},{"title":"API Scopes","href":"/api-reference/scopes"},{"group":"REST API","pages":[{"group":"synq.agent.recon.v1.YamlService","pages":[{"title":"ParseYaml","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/agent/recon/v1/yaml/parse","href":"/api-reference/synqagentreconv1yamlservice/parseyaml"},{"title":"RenderYaml","description":"RenderYaml renders a ReconciliationSuite proto as a YAML config string.","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/agent/recon/v1/yaml/render","href":"/api-reference/synqagentreconv1yamlservice/renderyaml"},{"title":"ValidateSuite","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/agent/recon/v1/yaml/validate","href":"/api-reference/synqagentreconv1yamlservice/validatesuite"}]},{"group":"synq.alerts.services.v1.AlertsService","pages":[{"title":"Update","description":"Update an existing alert configuration.\n The config can be identified by either ID or FQN.","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /api/alerts/v1","href":"/api-reference/synqalertsservicesv1alertsservice/update"},{"title":"Create","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v1","href":"/api-reference/synqalertsservicesv1alertsservice/create"},{"title":"Delete","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/alerts/v1","href":"/api-reference/synqalertsservicesv1alertsservice/delete"},{"title":"BatchGet","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v1/get","href":"/api-reference/synqalertsservicesv1alertsservice/batchget"},{"title":"List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v1/list","href":"/api-reference/synqalertsservicesv1alertsservice/list"},{"title":"ToggleEnabled","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v1/toggle","href":"/api-reference/synqalertsservicesv1alertsservice/toggleenabled"}]},{"group":"synq.alerts.services.v2.AlertsService","pages":[{"title":"Upsert","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /api/alerts/v2","href":"/api-reference/synqalertsservicesv2alertsservice/upsert"},{"title":"Create","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v2","href":"/api-reference/synqalertsservicesv2alertsservice/create"},{"title":"Delete","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/alerts/v2","href":"/api-reference/synqalertsservicesv2alertsservice/delete"},{"title":"BatchGet","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v2/get","href":"/api-reference/synqalertsservicesv2alertsservice/batchget"},{"title":"GetIncidentOwnerAlert","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/alerts/v2/incident-owner","href":"/api-reference/synqalertsservicesv2alertsservice/getincidentowneralert"},{"title":"ToggleIncidentOwnerAlert","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v2/incident-owner","href":"/api-reference/synqalertsservicesv2alertsservice/toggleincidentowneralert"},{"title":"List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v2/list","href":"/api-reference/synqalertsservicesv2alertsservice/list"},{"title":"Rename","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v2/rename","href":"/api-reference/synqalertsservicesv2alertsservice/rename"},{"title":"UpdateSettings","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v2/settings","href":"/api-reference/synqalertsservicesv2alertsservice/updatesettings"},{"title":"UpdateTargets","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v2/targets","href":"/api-reference/synqalertsservicesv2alertsservice/updatetargets"},{"title":"UpdateTemplate","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v2/template","href":"/api-reference/synqalertsservicesv2alertsservice/updatetemplate"},{"title":"SendTestAlert","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v2/test","href":"/api-reference/synqalertsservicesv2alertsservice/sendtestalert"},{"title":"ToggleEnabled","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/alerts/v2/toggle","href":"/api-reference/synqalertsservicesv2alertsservice/toggleenabled"}]},{"group":"synq.entities.changes.v1.ChangesService","pages":[{"title":"List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/changes/v1","href":"/api-reference/synqentitieschangesv1changesservice/list"},{"title":"BatchChange","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/changes/v1/by-id","href":"/api-reference/synqentitieschangesv1changesservice/batchchange"}]},{"group":"synq.entities.code.v1.CodeService","pages":[{"title":"ListCode","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/code/v1","href":"/api-reference/synqentitiescodev1codeservice/listcode"}]},{"group":"synq.entities.constraints.v1.TableConstraintsService","pages":[{"title":"GetTableConstraints","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/constraints/v1/table-constraints","href":"/api-reference/synqentitiesconstraintsv1tableconstraintsservice/gettableconstraints"}]},{"group":"synq.entities.coordinates.v1.DatabaseCoordinatesService","pages":[{"title":"BatchIdsByCoordinates","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/coordinates/v1/database/by-fqn","href":"/api-reference/synqentitiescoordinatesv1databasecoordinatesservice/batchidsbycoordinates"},{"title":"BatchDatabaseCoordinates","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/coordinates/v1/database/by-id","href":"/api-reference/synqentitiescoordinatesv1databasecoordinatesservice/batchdatabasecoordinates"}]},{"group":"synq.datachecks.v1.TriggerService","pages":[{"title":"TriggerDatachecks","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datachecks/scheduler/v1/trigger","href":"/api-reference/synqdatachecksv1triggerservice/triggerdatachecks"}]},{"group":"synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService","pages":[{"title":"ListSqlTestDeploymentRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/datachecks/sql-test-deployment-rules/v1","href":"/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/listsqltestdeploymentrules"},{"title":"BatchDeleteSqlTestDeploymentRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/datachecks/sql-test-deployment-rules/v1/batch","href":"/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/batchdeletesqltestdeploymentrules"},{"title":"BatchDeploySqlTestDeploymentRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datachecks/sql-test-deployment-rules/v1/batch/deployed","href":"/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/batchdeploysqltestdeploymentrules"},{"title":"BatchGetSqlTestDeploymentRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datachecks/sql-test-deployment-rules/v1/by-id","href":"/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/batchgetsqltestdeploymentrules"},{"title":"DeploySqlTestDeploymentRule","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datachecks/sql-test-deployment-rules/v1/deployed","href":"/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/deploysqltestdeploymentrule"},{"title":"GetSqlTestDeployOverview","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/datachecks/sql-test-deployment-rules/v1/overview","href":"/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/getsqltestdeployoverview"},{"title":"DeleteSqlTestDeploymentRule","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/datachecks/sql-test-deployment-rules/v1/{id}","href":"/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/deletesqltestdeploymentrule"},{"title":"GetSqlTestDeployDeleteOverview","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/datachecks/sql-test-deployment-rules/v1/{id}/deleted","href":"/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/getsqltestdeploydeleteoverview"}]},{"group":"synq.datachecks.sqltests.v1.SqlTestsService","pages":[{"title":"ListSqlTests","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/datachecks/sqltests/v1","href":"/api-reference/synqdatacheckssqltestsv1sqltestsservice/listsqltests"},{"title":"BatchUpsertSqlTests","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datachecks/sqltests/v1","href":"/api-reference/synqdatacheckssqltestsv1sqltestsservice/batchupsertsqltests"},{"title":"BatchDeleteSqlTests","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/datachecks/sqltests/v1","href":"/api-reference/synqdatacheckssqltestsv1sqltestsservice/batchdeletesqltests"},{"title":"BatchGetSqlTests","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datachecks/sqltests/v1/by-id","href":"/api-reference/synqdatacheckssqltestsv1sqltestsservice/batchgetsqltests"}]},{"group":"synq.datachecks.testsuggestions.v1.TestSuggestionsService","pages":[{"title":"BatchGetTestSuggestionsForEntities","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/datachecks/testsuggestions/v1","href":"/api-reference/synqdatacheckstestsuggestionsv1testsuggestionsservice/batchgettestsuggestionsforentities"},{"title":"BatchCreateTestSuggestions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datachecks/testsuggestions/v1","href":"/api-reference/synqdatacheckstestsuggestionsv1testsuggestionsservice/batchcreatetestsuggestions"},{"title":"BatchAcceptTestSuggestions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/datachecks/testsuggestions/v1/accepted","href":"/api-reference/synqdatacheckstestsuggestionsv1testsuggestionsservice/batchaccepttestsuggestions"},{"title":"BatchRejectTestSuggestions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/datachecks/testsuggestions/v1/rejected","href":"/api-reference/synqdatacheckstestsuggestionsv1testsuggestionsservice/batchrejecttestsuggestions"}]},{"group":"synq.dataproducts.v1.DataproductsService","pages":[{"title":"List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/dataproducts/v1","href":"/api-reference/synqdataproductsv1dataproductsservice/list"},{"title":"Upsert","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/dataproducts/v1","href":"/api-reference/synqdataproductsv1dataproductsservice/upsert"},{"title":"SetDefinition","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/dataproducts/v1/definition","href":"/api-reference/synqdataproductsv1dataproductsservice/setdefinition"},{"title":"UpsertDefinitionPart","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/dataproducts/v1/definition/part","href":"/api-reference/synqdataproductsv1dataproductsservice/upsertdefinitionpart"},{"title":"RemoveDefinitionPart","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/dataproducts/v1/definition/part/delete","href":"/api-reference/synqdataproductsv1dataproductsservice/removedefinitionpart"},{"title":"Delete","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/dataproducts/v1/delete","href":"/api-reference/synqdataproductsv1dataproductsservice/delete"},{"title":"Get","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/dataproducts/v1/get","href":"/api-reference/synqdataproductsv1dataproductsservice/get"}]},{"group":"synq.dataproducts.v2.DataproductsService","pages":[{"title":"List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/dataproducts/v2","href":"/api-reference/synqdataproductsv2dataproductsservice/list"},{"title":"Upsert","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/dataproducts/v2","href":"/api-reference/synqdataproductsv2dataproductsservice/upsert"},{"title":"BatchGet","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/dataproducts/v2/batch-get","href":"/api-reference/synqdataproductsv2dataproductsservice/batchget"},{"title":"Delete","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/dataproducts/v2/delete","href":"/api-reference/synqdataproductsv2dataproductsservice/delete"},{"title":"SetDefinition","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /api/dataproducts/v2/{id}/definition","href":"/api-reference/synqdataproductsv2dataproductsservice/setdefinition"},{"title":"UpsertDefinitionPart","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/dataproducts/v2/{id}/definition/parts","href":"/api-reference/synqdataproductsv2dataproductsservice/upsertdefinitionpart"},{"title":"RemoveDefinitionPart","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/dataproducts/v2/{id}/definition/parts/{part_id}","href":"/api-reference/synqdataproductsv2dataproductsservice/removedefinitionpart"},{"title":"ListMembers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/dataproducts/v2/{id}/members","href":"/api-reference/synqdataproductsv2dataproductsservice/listmembers"}]},{"group":"synq.ingest.dwh.v1.DwhService","pages":[{"title":"IngestTaskResults","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/task/{task_id}/task-results","href":"/api-reference/synqingestdwhv1dwhservice/ingesttaskresults"},{"title":"IngestLineage","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/lineage","href":"/api-reference/synqingestdwhv1dwhservice/ingestlineage"},{"title":"IngestObjectInformation","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/object-information","href":"/api-reference/synqingestdwhv1dwhservice/ingestobjectinformation"},{"title":"IngestObjectMetrics","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/object-metrics","href":"/api-reference/synqingestdwhv1dwhservice/ingestobjectmetrics"},{"title":"IngestQueryLogs","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/query-logs","href":"/api-reference/synqingestdwhv1dwhservice/ingestquerylogs"},{"title":"IngestSchemas","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/schemas","href":"/api-reference/synqingestdwhv1dwhservice/ingestschemas"},{"title":"IngestSqlDefinitions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/sql-definitions","href":"/api-reference/synqingestdwhv1dwhservice/ingestsqldefinitions"},{"title":"IngestTableConstraints","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/table-constraints","href":"/api-reference/synqingestdwhv1dwhservice/ingesttableconstraints"}]},{"group":"synq.deliveries.v1.DeliveriesService","pages":[{"title":"ListDeliveries","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/deliveries/v1","href":"/api-reference/synqdeliveriesv1deliveriesservice/listdeliveries"},{"title":"BatchGetDeliveries","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/deliveries/v1/by-id","href":"/api-reference/synqdeliveriesv1deliveriesservice/batchgetdeliveries"},{"title":"SummariseDeliveries","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/deliveries/v1/summarise","href":"/api-reference/synqdeliveriesv1deliveriesservice/summarisedeliveries"},{"title":"SendTestDelivery","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/deliveries/v1/test","href":"/api-reference/synqdeliveriesv1deliveriesservice/sendtestdelivery"},{"title":"ListAttempts","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/deliveries/v1/{delivery_id}/attempts","href":"/api-reference/synqdeliveriesv1deliveriesservice/listattempts"},{"title":"Redeliver","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/deliveries/v1/{delivery_id}/redeliver","href":"/api-reference/synqdeliveriesv1deliveriesservice/redeliver"}]},{"group":"synq.domains.members.v1.DomainMembersService","pages":[{"title":"ListUserDomains","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/domains/members/v1/users/{user_id}/domains","href":"/api-reference/synqdomainsmembersv1domainmembersservice/listuserdomains"},{"title":"SetDefaultUserDomain","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/members/v1/{domain_id}/default-for-user","href":"/api-reference/synqdomainsmembersv1domainmembersservice/setdefaultuserdomain"},{"title":"ListDomainMembers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/domains/members/v1/{domain_id}/members","href":"/api-reference/synqdomainsmembersv1domainmembersservice/listdomainmembers"},{"title":"AddDomainMembers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/members/v1/{domain_id}/members","href":"/api-reference/synqdomainsmembersv1domainmembersservice/adddomainmembers"},{"title":"RemoveDomainMembers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/members/v1/{domain_id}/members/remove","href":"/api-reference/synqdomainsmembersv1domainmembersservice/removedomainmembers"}]},{"group":"synq.domains.v1.DomainsService","pages":[{"title":"List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/domains/v1","href":"/api-reference/synqdomainsv1domainsservice/list"},{"title":"Upsert","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/v1","href":"/api-reference/synqdomainsv1domainsservice/upsert"},{"title":"BatchGet","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/v1/batch-get","href":"/api-reference/synqdomainsv1domainsservice/batchget"},{"title":"Delete","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/v1/delete","href":"/api-reference/synqdomainsv1domainsservice/delete"},{"title":"GetUsage","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/domains/v1/usage","href":"/api-reference/synqdomainsv1domainsservice/getusage"},{"title":"SetDefinition","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /api/domains/v1/{domain_id}/definition","href":"/api-reference/synqdomainsv1domainsservice/setdefinition"},{"title":"UpsertDefinitionPart","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/v1/{domain_id}/definition/parts","href":"/api-reference/synqdomainsv1domainsservice/upsertdefinitionpart"},{"title":"RemoveDefinitionPart","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/domains/v1/{domain_id}/definition/parts/{part_id}","href":"/api-reference/synqdomainsv1domainsservice/removedefinitionpart"},{"title":"FetchDomainWithSubDomains","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/domains/v1/{domain_id}/sub-domains","href":"/api-reference/synqdomainsv1domainsservice/fetchdomainwithsubdomains"}]},{"group":"synq.domains.v2.DomainsService","pages":[{"title":"List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/domains/v2","href":"/api-reference/synqdomainsv2domainsservice/list"},{"title":"Upsert","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/v2","href":"/api-reference/synqdomainsv2domainsservice/upsert"},{"title":"BatchGet","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/v2/batch-get","href":"/api-reference/synqdomainsv2domainsservice/batchget"},{"title":"Delete","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/v2/delete","href":"/api-reference/synqdomainsv2domainsservice/delete"},{"title":"GetUsage","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/domains/v2/usage","href":"/api-reference/synqdomainsv2domainsservice/getusage"},{"title":"SetDefinition","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /api/domains/v2/{id}/definition","href":"/api-reference/synqdomainsv2domainsservice/setdefinition"},{"title":"UpsertDefinitionPart","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/domains/v2/{id}/definition/parts","href":"/api-reference/synqdomainsv2domainsservice/upsertdefinitionpart"},{"title":"RemoveDefinitionPart","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/domains/v2/{id}/definition/parts/{part_id}","href":"/api-reference/synqdomainsv2domainsservice/removedefinitionpart"},{"title":"ListMembers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/domains/v2/{id}/members","href":"/api-reference/synqdomainsv2domainsservice/listmembers"},{"title":"FetchDomainWithSubDomains","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/domains/v2/{id}/sub-domains","href":"/api-reference/synqdomainsv2domainsservice/fetchdomainwithsubdomains"}]},{"group":"synq.entities.activity.v1alpha.ActivityService","pages":[{"title":"ListActors","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/activity/v1alpha/actor-list","href":"/api-reference/synqentitiesactivityv1alphaactivityservice/listactors"},{"title":"GetActorSummary","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/activity/v1alpha/actor-summary","href":"/api-reference/synqentitiesactivityv1alphaactivityservice/getactorsummary"},{"title":"ListEntityActors","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/activity/v1alpha/actors","href":"/api-reference/synqentitiesactivityv1alphaactivityservice/listentityactors"},{"title":"GetActivityOverview","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/activity/v1alpha/overview","href":"/api-reference/synqentitiesactivityv1alphaactivityservice/getactivityoverview"},{"title":"ListPersonActivity","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/activity/v1alpha/person","href":"/api-reference/synqentitiesactivityv1alphaactivityservice/listpersonactivity"},{"title":"BatchGetPopularity","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/activity/v1alpha/popularity","href":"/api-reference/synqentitiesactivityv1alphaactivityservice/batchgetpopularity"},{"title":"GetEntityActivitySeries","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/activity/v1alpha/series","href":"/api-reference/synqentitiesactivityv1alphaactivityservice/getentityactivityseries"},{"title":"ListAccessSignals","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/activity/v1alpha/signals","href":"/api-reference/synqentitiesactivityv1alphaactivityservice/listaccesssignals"},{"title":"BatchGetEntityUsage","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/activity/v1alpha/usage","href":"/api-reference/synqentitiesactivityv1alphaactivityservice/batchgetentityusage"}]},{"group":"synq.entities.annotations.v1.AnnotationsService","pages":[{"title":"ListAnnotations","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/entities/annotations/v1","href":"/api-reference/synqentitiesannotationsv1annotationsservice/listannotations"},{"title":"BatchGetEntityAnnotations","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/annotations/v1/batchGet","href":"/api-reference/synqentitiesannotationsv1annotationsservice/batchgetentityannotations"}]},{"group":"synq.entities.checks.v1.ChecksCategoriesService","pages":[{"title":"ListCheckCategories","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/entities/checks/v1/categories","href":"/api-reference/synqentitieschecksv1checkscategoriesservice/listcheckcategories"},{"title":"DeleteCheckCategories","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/checks/v1/categories:delete","href":"/api-reference/synqentitieschecksv1checkscategoriesservice/deletecheckcategories"},{"title":"UpsertCheckCategories","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/checks/v1/categories:upsert","href":"/api-reference/synqentitieschecksv1checkscategoriesservice/upsertcheckcategories"}]},{"group":"synq.entities.custom.v1.EntityExecutionsService","pages":[{"title":"UpsertExecution","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/executions/v1","href":"/api-reference/synqentitiescustomv1entityexecutionsservice/upsertexecution"},{"title":"UpsertLogEntry","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/executions/v1/log-entry","href":"/api-reference/synqentitiescustomv1entityexecutionsservice/upsertlogentry"}]},{"group":"synq.entities.custom.v1.ChecksRelationshipsService","pages":[{"title":"UpsertCheckRelationships","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/check-relationships","href":"/api-reference/synqentitiescustomv1checksrelationshipsservice/upsertcheckrelationships"},{"title":"DeleteCheckRelationships","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/entities/custom/v1/check-relationships","href":"/api-reference/synqentitiescustomv1checksrelationshipsservice/deletecheckrelationships"},{"title":"ListCheckRelationships","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/check-relationships/list","href":"/api-reference/synqentitiescustomv1checksrelationshipsservice/listcheckrelationships"}]},{"group":"synq.entities.custom.v1.EntitiesService","pages":[{"title":"ListEntities","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/entities/custom/v1/entities","href":"/api-reference/synqentitiescustomv1entitiesservice/listentities"},{"title":"UpsertEntity","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/entities","href":"/api-reference/synqentitiescustomv1entitiesservice/upsertentity"},{"title":"DeleteEntity","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/entities/custom/v1/entities","href":"/api-reference/synqentitiescustomv1entitiesservice/deleteentity"}]},{"group":"synq.entities.custom.v1.FeaturesService","pages":[{"title":"UpsertEntityFeature","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/features","href":"/api-reference/synqentitiescustomv1featuresservice/upsertentityfeature"},{"title":"DeleteEntityFeature","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/entities/custom/v1/features","href":"/api-reference/synqentitiescustomv1featuresservice/deleteentityfeature"},{"title":"ListEntityFeatures","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/features/list","href":"/api-reference/synqentitiescustomv1featuresservice/listentityfeatures"}]},{"group":"synq.entities.custom.v1.GroupsService","pages":[{"title":"UpsertEntitiesGroup","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/groups","href":"/api-reference/synqentitiescustomv1groupsservice/upsertentitiesgroup"},{"title":"DeleteEntitiesGroup","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/entities/custom/v1/groups","href":"/api-reference/synqentitiescustomv1groupsservice/deleteentitiesgroup"},{"title":"ListEntityGroups","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/groups/list","href":"/api-reference/synqentitiescustomv1groupsservice/listentitygroups"}]},{"group":"synq.entities.custom.v1.RelationshipsService","pages":[{"title":"UpsertRelationships","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/relationships","href":"/api-reference/synqentitiescustomv1relationshipsservice/upsertrelationships"},{"title":"DeleteRelationships","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/entities/custom/v1/relationships","href":"/api-reference/synqentitiescustomv1relationshipsservice/deleterelationships"},{"title":"ListRelationships","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/relationships/list","href":"/api-reference/synqentitiescustomv1relationshipsservice/listrelationships"}]},{"group":"synq.entities.custom.v1.TypesService","pages":[{"title":"UpsertType","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/types","href":"/api-reference/synqentitiescustomv1typesservice/upserttype"},{"title":"DeleteType","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/entities/custom/v1/types","href":"/api-reference/synqentitiescustomv1typesservice/deletetype"},{"title":"ListTypes","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/custom/v1/types/list","href":"/api-reference/synqentitiescustomv1typesservice/listtypes"}]},{"group":"synq.entities.folders.v1.FoldersService","pages":[{"title":"Browse","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/entities/folders/v1/browse","href":"/api-reference/synqentitiesfoldersv1foldersservice/browse"},{"title":"GetFolderOf","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/entities/folders/v1/folder-of","href":"/api-reference/synqentitiesfoldersv1foldersservice/getfolderof"},{"title":"ListMembers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/entities/folders/v1/members","href":"/api-reference/synqentitiesfoldersv1foldersservice/listmembers"}]},{"group":"synq.entities.platformusers.v1alpha.PlatformUsersService","pages":[{"title":"BatchGetPlatformUsers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/platform-users/v1alpha/batch-get","href":"/api-reference/synqentitiesplatformusersv1alphaplatformusersservice/batchgetplatformusers"},{"title":"ListLinkSuggestions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/platform-users/v1alpha/link-suggestions","href":"/api-reference/synqentitiesplatformusersv1alphaplatformusersservice/listlinksuggestions"},{"title":"ListPlatformUsers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/platform-users/v1alpha/list","href":"/api-reference/synqentitiesplatformusersv1alphaplatformusersservice/listplatformusers"}]},{"group":"synq.entities.platformusers.v1alpha.ServiceAccountsService","pages":[{"title":"ApplyServiceAccountChanges","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/service-accounts/v1alpha/apply","href":"/api-reference/synqentitiesplatformusersv1alphaserviceaccountsservice/applyserviceaccountchanges"},{"title":"BatchGetServiceAccounts","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/service-accounts/v1alpha/batch-get","href":"/api-reference/synqentitiesplatformusersv1alphaserviceaccountsservice/batchgetserviceaccounts"},{"title":"ListServiceAccounts","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/service-accounts/v1alpha/list","href":"/api-reference/synqentitiesplatformusersv1alphaserviceaccountsservice/listserviceaccounts"},{"title":"PlanServiceAccountChanges","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/service-accounts/v1alpha/plan","href":"/api-reference/synqentitiesplatformusersv1alphaserviceaccountsservice/planserviceaccountchanges"},{"title":"ListServiceAccountSuggestions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/service-accounts/v1alpha/suggestions","href":"/api-reference/synqentitiesplatformusersv1alphaserviceaccountsservice/listserviceaccountsuggestions"}]},{"group":"synq.entities.tableinfo.v1alpha.TableInfoService","pages":[{"title":"BatchGetTableInfo","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/table-info/v1alpha/batch-get","href":"/api-reference/synqentitiestableinfov1alphatableinfoservice/batchgettableinfo"}]},{"group":"synq.entities.typedefs.v1.TypeDefsService","pages":[{"title":"ListEntityTraitDefs","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/typedefs/v1/entity-traits/list","href":"/api-reference/synqentitiestypedefsv1typedefsservice/listentitytraitdefs"},{"title":"ListEntityTypeDefs","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/typedefs/v1/entity-types/list","href":"/api-reference/synqentitiestypedefsv1typedefsservice/listentitytypedefs"},{"title":"ListExecutionTypeDefs","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/typedefs/v1/execution-types/list","href":"/api-reference/synqentitiestypedefsv1typedefsservice/listexecutiontypedefs"},{"title":"ListPlatformDefs","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/typedefs/v1/platforms/list","href":"/api-reference/synqentitiestypedefsv1typedefsservice/listplatformdefs"}]},{"group":"synq.entities.entities.v1.EntitiesService","pages":[{"title":"ListEntities","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/entities/v1","href":"/api-reference/synqentitiesentitiesv1entitiesservice/listentities"},{"title":"BatchGetEntities","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v1/by-id","href":"/api-reference/synqentitiesentitiesv1entitiesservice/batchgetentities"},{"title":"SearchEntities","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/entities/v1/search","href":"/api-reference/synqentitiesentitiesv1entitiesservice/searchentities"}]},{"group":"synq.entities.checks.v2.ChecksCategoriesService","pages":[{"title":"UpsertCheckCategories","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categories","href":"/api-reference/synqentitieschecksv2checkscategoriesservice/upsertcheckcategories"},{"title":"BatchGetCheckCategories","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categories/batch-get","href":"/api-reference/synqentitieschecksv2checkscategoriesservice/batchgetcheckcategories"},{"title":"DeleteCheckCategories","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categories/delete","href":"/api-reference/synqentitieschecksv2checkscategoriesservice/deletecheckcategories"},{"title":"ListCategorisationFilters","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categories/filters","href":"/api-reference/synqentitieschecksv2checkscategoriesservice/listcategorisationfilters"},{"title":"ListCheckCategories","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categories/list","href":"/api-reference/synqentitieschecksv2checkscategoriesservice/listcheckcategories"},{"title":"ListCategories","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categories/vocabulary","href":"/api-reference/synqentitieschecksv2checkscategoriesservice/listcategories"}]},{"group":"synq.entities.checks.v2.ChecksCategorisationRulesService","pages":[{"title":"UpsertRule","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules","href":"/api-reference/synqentitieschecksv2checkscategorisationrulesservice/upsertrule"},{"title":"BatchGetRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/batch-get","href":"/api-reference/synqentitieschecksv2checkscategorisationrulesservice/batchgetrules"},{"title":"DeleteRule","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/delete","href":"/api-reference/synqentitieschecksv2checkscategorisationrulesservice/deleterule"},{"title":"ListRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/list","href":"/api-reference/synqentitieschecksv2checkscategorisationrulesservice/listrules"},{"title":"ListRuleMatches","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/matches","href":"/api-reference/synqentitieschecksv2checkscategorisationrulesservice/listrulematches"},{"title":"PreviewRule","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/preview","href":"/api-reference/synqentitieschecksv2checkscategorisationrulesservice/previewrule"},{"title":"GetRecategorisationStatus","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/recategorisation-status","href":"/api-reference/synqentitieschecksv2checkscategorisationrulesservice/getrecategorisationstatus"}]},{"group":"synq.entities.executions.v1.EntityExecutionsService","pages":[{"title":"UpsertExecution","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/executions/v1","href":"/api-reference/synqentitiesexecutionsv1entityexecutionsservice/upsertexecution"},{"title":"UpsertLogEntry","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/executions/v1/log-entry","href":"/api-reference/synqentitiesexecutionsv1entityexecutionsservice/upsertlogentry"}]},{"group":"synq.entities.executions.v2.EntityExecutionsService","pages":[{"title":"BatchGetExecutions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/executions/v2/by-id","href":"/api-reference/synqentitiesexecutionsv2entityexecutionsservice/batchgetexecutions"},{"title":"GetLatestExecutions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/executions/v2/latest","href":"/api-reference/synqentitiesexecutionsv2entityexecutionsservice/getlatestexecutions"},{"title":"ListExecutions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/executions/v2/list","href":"/api-reference/synqentitiesexecutionsv2entityexecutionsservice/listexecutions"},{"title":"GetExecutionsSummary","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/executions/v2/summary","href":"/api-reference/synqentitiesexecutionsv2entityexecutionsservice/getexecutionssummary"}]},{"group":"synq.extensions.atlan.integrations.v1.AtlanIntegrationService","pages":[{"title":"Get","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/extensions/atlan/integrations/v1","href":"/api-reference/synqextensionsatlanintegrationsv1atlanintegrationservice/get"},{"title":"Upsert","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/extensions/atlan/integrations/v1","href":"/api-reference/synqextensionsatlanintegrationsv1atlanintegrationservice/upsert"},{"title":"Remove","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/extensions/atlan/integrations/v1","href":"/api-reference/synqextensionsatlanintegrationsv1atlanintegrationservice/remove"},{"title":"Activate","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/extensions/atlan/integrations/v1","href":"/api-reference/synqextensionsatlanintegrationsv1atlanintegrationservice/activate"},{"title":"Ping","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/extensions/atlan/integrations/v1/ping","href":"/api-reference/synqextensionsatlanintegrationsv1atlanintegrationservice/ping"}]},{"group":"synq.extensions.atlan.provider.v1.AtlanProviderService","pages":[{"title":"GetAtlanConnections","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/extensions/atlan/provider/v1/connections","href":"/api-reference/synqextensionsatlanproviderv1atlanproviderservice/getatlanconnections"},{"title":"GetAtlanDataProducts","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/extensions/atlan/provider/v1/data-products","href":"/api-reference/synqextensionsatlanproviderv1atlanproviderservice/getatlandataproducts"},{"title":"GetAtlanDomains","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/extensions/atlan/provider/v1/domains","href":"/api-reference/synqextensionsatlanproviderv1atlanproviderservice/getatlandomains"}]},{"group":"synq.extensions.atlan.workflows.v1.AtlanWorkflowService","pages":[{"title":"GetConnectionMappings","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/extensions/atlan/workflows/v1/connection-mappings","href":"/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/getconnectionmappings"},{"title":"SetConnectionMappings","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/extensions/atlan/workflows/v1/connection-mappings","href":"/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/setconnectionmappings"},{"title":"RemoveConnectionMappings","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/extensions/atlan/workflows/v1/connection-mappings","href":"/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/removeconnectionmappings"},{"title":"GetDomainMappings","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/extensions/atlan/workflows/v1/domain-mappings","href":"/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/getdomainmappings"},{"title":"GetMappingToggles","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/extensions/atlan/workflows/v1/mappings/toggle","href":"/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/getmappingtoggles"},{"title":"SetMappingToggles","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/extensions/atlan/workflows/v1/mappings/toggle","href":"/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/setmappingtoggles"},{"title":"GetProductMappings","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/extensions/atlan/workflows/v1/product-mappings","href":"/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/getproductmappings"},{"title":"FetchRuns","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/extensions/atlan/workflows/v1/runs","href":"/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/fetchruns"},{"title":"Synchronize","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/extensions/atlan/workflows/v1/synchronize","href":"/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/synchronize"}]},{"group":"synq.agent.sre.v1.FeatureRequestService","pages":[{"title":"SubmitFeatureRequest","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/feature-request/v1/submit","href":"/api-reference/synqagentsrev1featurerequestservice/submitfeaturerequest"}]},{"group":"synq.git.commits.v1.CommitsService","pages":[{"title":"GetDiffByChangeId","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/git/v1/change/{change_id}","href":"/api-reference/synqgitcommitsv1commitsservice/getdiffbychangeid"},{"title":"GetDiffByCommit","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/git/v1/commit/{commit_sha}","href":"/api-reference/synqgitcommitsv1commitsservice/getdiffbycommit"}]},{"group":"synq.auth.iam.v1.IamService","pages":[{"title":"Iam","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/iam/v1","href":"/api-reference/synqauthiamv1iamservice/iam"}]},{"group":"synq.entities.impact.v1.ImpactService","pages":[{"title":"GetImpact","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/impact/v1","href":"/api-reference/synqentitiesimpactv1impactservice/getimpact"}]},{"group":"synq.incidents.v1.IncidentsService","pages":[{"title":"ListIncidents","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/incidents/v1","href":"/api-reference/synqincidentsv1incidentsservice/listincidents"},{"title":"CreateIncident","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/incidents/v1","href":"/api-reference/synqincidentsv1incidentsservice/createincident"},{"title":"BatchGetIncidents","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/incidents/v1/by-id","href":"/api-reference/synqincidentsv1incidentsservice/batchgetincidents"},{"title":"AssignIncidentOwner","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/incidents/v1/{incident_id}/assign-owner","href":"/api-reference/synqincidentsv1incidentsservice/assignincidentowner"},{"title":"CancelIncident","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/incidents/v1/{incident_id}/cancel","href":"/api-reference/synqincidentsv1incidentsservice/cancelincident"},{"title":"CloseIncident","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/incidents/v1/{incident_id}/close","href":"/api-reference/synqincidentsv1incidentsservice/closeincident"},{"title":"PostComment","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/incidents/v1/{incident_id}/comment","href":"/api-reference/synqincidentsv1incidentsservice/postcomment"},{"title":"DeleteComment","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/incidents/v1/{incident_id}/comment/{comment_id}","href":"/api-reference/synqincidentsv1incidentsservice/deletecomment"},{"title":"AddIssuesToIncident","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/incidents/v1/{incident_id}/issues","href":"/api-reference/synqincidentsv1incidentsservice/addissuestoincident"},{"title":"RemoveIssuesFromIncident","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/incidents/v1/{incident_id}/issues","href":"/api-reference/synqincidentsv1incidentsservice/removeissuesfromincident"},{"title":"MergeIncidents","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/incidents/v1/{incident_id}/merge","href":"/api-reference/synqincidentsv1incidentsservice/mergeincidents"},{"title":"RenameIncident","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/incidents/v1/{incident_id}/rename","href":"/api-reference/synqincidentsv1incidentsservice/renameincident"},{"title":"SplitIncident","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/incidents/v1/{incident_id}/split","href":"/api-reference/synqincidentsv1incidentsservice/splitincident"},{"title":"UpdateIncidentState","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/incidents/v1/{incident_id}/state","href":"/api-reference/synqincidentsv1incidentsservice/updateincidentstate"}]},{"group":"synq.ingest.airflow.v1.AirflowLogsService","pages":[{"title":"IngestDatahubAspects","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/ingest/airflow/v1/aspects","href":"/api-reference/synqingestairflowv1airflowlogsservice/ingestdatahubaspects"},{"title":"IngestLog","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/ingest/airflow/v1/{dag_id}/{task_id}/{run_id}/logs","href":"/api-reference/synqingestairflowv1airflowlogsservice/ingestlog"}]},{"group":"synq.ingest.cloudwatch.v1.CloudwatchService","pages":[{"title":"IngestCloudwatchLogsData","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/ingest/cloudwatch/v1/{log_group}/{log_stream}","href":"/api-reference/synqingestcloudwatchv1cloudwatchservice/ingestcloudwatchlogsdata"}]},{"group":"synq.ingest.openlineage.v1.OpenlineageService","pages":[{"title":"Ingest","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/ingest/openlineage/v1","href":"/api-reference/synqingestopenlineagev1openlineageservice/ingest"}]},{"group":"synq.integrations.v1.IntegrationsService","pages":[{"title":"ListIntegrations","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/integrations/v1","href":"/api-reference/synqintegrationsv1integrationsservice/listintegrations"},{"title":"CreateIntegration","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/integrations/v1","href":"/api-reference/synqintegrationsv1integrationsservice/createintegration"},{"title":"BatchGetIntegrations","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/integrations/v1/by-id","href":"/api-reference/synqintegrationsv1integrationsservice/batchgetintegrations"},{"title":"UpdateIntegration","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /api/integrations/v1/{integration_id}","href":"/api-reference/synqintegrationsv1integrationsservice/updateintegration"},{"title":"DeleteIntegration","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/integrations/v1/{integration_id}","href":"/api-reference/synqintegrationsv1integrationsservice/deleteintegration"},{"title":"DisableIntegration","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/integrations/v1/{integration_id}/disable","href":"/api-reference/synqintegrationsv1integrationsservice/disableintegration"},{"title":"EnableIntegration","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/integrations/v1/{integration_id}/enable","href":"/api-reference/synqintegrationsv1integrationsservice/enableintegration"},{"title":"RefreshIntegration","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/integrations/v1/{integration_id}/refresh","href":"/api-reference/synqintegrationsv1integrationsservice/refreshintegration"}]},{"group":"synq.issues.issues.v1.IssuesService","pages":[{"title":"ListIssues","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/issues/v1","href":"/api-reference/synqissuesissuesv1issuesservice/listissues"},{"title":"BatchGetIssues","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/issues/v1/by-id","href":"/api-reference/synqissuesissuesv1issuesservice/batchgetissues"},{"title":"PostComment","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/issues/v1/{issue_id}/comment","href":"/api-reference/synqissuesissuesv1issuesservice/postcomment"},{"title":"MarkExpected","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/issues/v1/{issue_id}/mark-expected","href":"/api-reference/synqissuesissuesv1issuesservice/markexpected"},{"title":"MarkFixed","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/issues/v1/{issue_id}/mark-fixed","href":"/api-reference/synqissuesissuesv1issuesservice/markfixed"},{"title":"MarkInvestigating","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/issues/v1/{issue_id}/mark-investigating","href":"/api-reference/synqissuesissuesv1issuesservice/markinvestigating"},{"title":"MarkNoActionNeeded","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/issues/v1/{issue_id}/mark-no-action-needed","href":"/api-reference/synqissuesissuesv1issuesservice/marknoactionneeded"}]},{"group":"synq.issues.v2.IssuesService","pages":[{"title":"ListIssues","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/issues/v2","href":"/api-reference/synqissuesv2issuesservice/listissues"},{"title":"BatchGetIssues","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/issues/v2/by-id","href":"/api-reference/synqissuesv2issuesservice/batchgetissues"},{"title":"ClearStatus","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/issues/v2/{issue_id}/clear-status","href":"/api-reference/synqissuesv2issuesservice/clearstatus"},{"title":"PostComment","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/issues/v2/{issue_id}/comment","href":"/api-reference/synqissuesv2issuesservice/postcomment"},{"title":"DeleteComment","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/issues/v2/{issue_id}/comment/{comment_id}","href":"/api-reference/synqissuesv2issuesservice/deletecomment"},{"title":"MarkExpected","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/issues/v2/{issue_id}/mark-expected","href":"/api-reference/synqissuesv2issuesservice/markexpected"},{"title":"MarkFixed","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/issues/v2/{issue_id}/mark-fixed","href":"/api-reference/synqissuesv2issuesservice/markfixed"},{"title":"MarkInvestigating","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/issues/v2/{issue_id}/mark-investigating","href":"/api-reference/synqissuesv2issuesservice/markinvestigating"},{"title":"MarkNoActionNeeded","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/issues/v2/{issue_id}/mark-no-action-needed","href":"/api-reference/synqissuesv2issuesservice/marknoactionneeded"}]},{"group":"synq.knowledge.v1alpha.KnowledgeService","pages":[{"title":"BatchGetEntityKnowledge","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/knowledge/v1alpha/entities/by-id","href":"/api-reference/synqknowledgev1alphaknowledgeservice/batchgetentityknowledge"},{"title":"ListKnowledgePages","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/knowledge/v1alpha/pages","href":"/api-reference/synqknowledgev1alphaknowledgeservice/listknowledgepages"},{"title":"BatchGetKnowledgePages","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/knowledge/v1alpha/pages/by-id","href":"/api-reference/synqknowledgev1alphaknowledgeservice/batchgetknowledgepages"},{"title":"ListKnowledgePageLinks","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/knowledge/v1alpha/pages/{page_id}/links","href":"/api-reference/synqknowledgev1alphaknowledgeservice/listknowledgepagelinks"}]},{"group":"synq.entities.lineage.folds.v1alpha.LineageFoldsService","pages":[{"title":"ListFolds","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/lineage/folds/v1alpha","href":"/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/listfolds"},{"title":"CreateFold","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/lineage/folds/v1alpha","href":"/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/createfold"},{"title":"BatchGetFolds","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/lineage/folds/v1alpha/batch-get","href":"/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/batchgetfolds"},{"title":"BatchGetFoldNodes","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/lineage/folds/v1alpha/nodes/batch-get","href":"/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/batchgetfoldnodes"},{"title":"PreviewFold","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/lineage/folds/v1alpha/preview","href":"/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/previewfold"},{"title":"DeleteFold","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/lineage/folds/v1alpha/{id}/delete","href":"/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/deletefold"},{"title":"SetFoldEnabled","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/lineage/folds/v1alpha/{id}/enabled","href":"/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/setfoldenabled"},{"title":"UpdateFoldMatcher","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/lineage/folds/v1alpha/{id}/matcher","href":"/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/updatefoldmatcher"},{"title":"RenameFold","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/lineage/folds/v1alpha/{id}/rename","href":"/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/renamefold"}]},{"group":"synq.entities.lineage.v1.LineageService","pages":[{"title":"GetLineage","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/lineage/v1","href":"/api-reference/synqentitieslineagev1lineageservice/getlineage"}]},{"group":"synq.monitors.automated_monitors.v1.DeploymentRulesService","pages":[{"title":"GetDeployOverview","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/automated/v1/deployment-rule","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/getdeployoverview"},{"title":"DeleteDeploymentRule","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/monitors/automated/v1/deployment-rule/{id}","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/deletedeploymentrule"},{"title":"GetDeployDeleteOverview","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/automated/v1/deployment-rule/{id}/deleted","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/getdeploydeleteoverview"},{"title":"ListDeploymentRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/automated/v1/deployment-rules","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/listdeploymentrules"},{"title":"UpsertDeploymentRule","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/automated/v1/deployment-rules","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/upsertdeploymentrule"},{"title":"BatchUpdateDeploymentRuleTitle","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/monitors/automated/v1/deployment-rules","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/batchupdatedeploymentruletitle"},{"title":"BatchGetDeploymentRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/automated/v1/deployment-rules/batch","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/batchgetdeploymentrules"},{"title":"BatchUpsertDeploymentRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/automated/v1/deployment-rules/batch","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/batchupsertdeploymentrules"},{"title":"BatchDeleteDeploymentRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api/monitors/automated/v1/deployment-rules/batch","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/batchdeletedeploymentrules"},{"title":"BatchDeployDeploymentRules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/automated/v1/deployment-rules/batch/deployed","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/batchdeploydeploymentrules"},{"title":"DeployDeploymentRule","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/automated/v1/deployment-rules/deployed","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/deploydeploymentrule"},{"title":"ListDeploymentRulesForAsset","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/automated/v1/deployment-rules/{asset_path}","href":"/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/listdeploymentrulesforasset"}]},{"group":"synq.monitors.custom_monitors.v1.CustomMonitorsService","pages":[{"title":"ListMonitors","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/custom-monitors/v1","href":"/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/listmonitors"},{"title":"BatchUpdateMonitor","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /api/monitors/custom-monitors/v1","href":"/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/batchupdatemonitor"},{"title":"BatchCreateMonitor","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/custom-monitors/v1","href":"/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/batchcreatemonitor"},{"title":"ListConfigsMonitors","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/custom-monitors/v1/by-config","href":"/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/listconfigsmonitors"},{"title":"ConfigChangesOverview","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/custom-monitors/v1/config-changes","href":"/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/configchangesoverview"},{"title":"BatchDeleteMonitor","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/custom-monitors/v1/delete","href":"/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/batchdeletemonitor"},{"title":"BatchUpdateMonitorMode","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/custom-monitors/v1/mode","href":"/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/batchupdatemonitormode"},{"title":"BatchUpdateMonitorSeverity","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/custom-monitors/v1/severity","href":"/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/batchupdatemonitorseverity"}]},{"group":"synq.monitors.history.v1.HistoryService","pages":[{"title":"History","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/history/v1","href":"/api-reference/synqmonitorshistoryv1historyservice/history"}]},{"group":"synq.monitors.info.v1.MonitorInfoService","pages":[{"title":"MonitorInfo","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/info/v1","href":"/api-reference/synqmonitorsinfov1monitorinfoservice/monitorinfo"}]},{"group":"synq.monitors.predictions.v1.MonitorPredictionsService","pages":[{"title":"GetMonitorPredictions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/predictions/v1","href":"/api-reference/synqmonitorspredictionsv1monitorpredictionsservice/getmonitorpredictions"},{"title":"GetEntityMetrics","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/predictions/v1/entity-metrics","href":"/api-reference/synqmonitorspredictionsv1monitorpredictionsservice/getentitymetrics"},{"title":"BatchGetLatestEntityMetrics","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/predictions/v1/entity-metrics:batchLatest","href":"/api-reference/synqmonitorspredictionsv1monitorpredictionsservice/batchgetlatestentitymetrics"}]},{"group":"synq.monitors.segments.v1.MonitorSegmentsService","pages":[{"title":"ListMonitorSegments","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/monitors/segments/v1","href":"/api-reference/synqmonitorssegmentsv1monitorsegmentsservice/listmonitorsegments"},{"title":"BatchUpdateMonitorSegmentLabels","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/monitors/segments/v1/labels","href":"/api-reference/synqmonitorssegmentsv1monitorsegmentsservice/batchupdatemonitorsegmentlabels"}]},{"group":"synq.entities.orchestration.v1.OrchestrationService","pages":[{"title":"BatchOrchestration","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/orchestration/v1","href":"/api-reference/synqentitiesorchestrationv1orchestrationservice/batchorchestration"}]},{"group":"synq.overlays.v1.OverlaysService","pages":[{"title":"BatchGetEntityOverlays","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/overlays/v1/by-id","href":"/api-reference/synqoverlaysv1overlaysservice/batchgetentityoverlays"},{"title":"ListEntityCoverage","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/overlays/v1/coverage","href":"/api-reference/synqoverlaysv1overlaysservice/listentitycoverage"},{"title":"GetCoverageSummary","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/overlays/v1/coverage-summary","href":"/api-reference/synqoverlaysv1overlaysservice/getcoveragesummary"},{"title":"BatchGetOverlayMemberCounts","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/overlays/v1/member-counts","href":"/api-reference/synqoverlaysv1overlaysservice/batchgetoverlaymembercounts"}]},{"group":"synq.owners.v1.OwnersService","pages":[{"title":"ListOwners","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/owners/v1","href":"/api-reference/synqownersv1ownersservice/listowners"},{"title":"UpsertOwner","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/owners/v1","href":"/api-reference/synqownersv1ownersservice/upsertowner"},{"title":"BatchGetOwners","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/owners/v1/batch-get","href":"/api-reference/synqownersv1ownersservice/batchgetowners"},{"title":"DeleteOwner","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/owners/v1/delete","href":"/api-reference/synqownersv1ownersservice/deleteowner"},{"title":"BatchGetOwnerships","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/owners/v1/ownerships/batch-get","href":"/api-reference/synqownersv1ownersservice/batchgetownerships"},{"title":"DeleteOwnership","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/owners/v1/ownerships/delete","href":"/api-reference/synqownersv1ownersservice/deleteownership"},{"title":"ListOwnerships","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/owners/v1/{owner_id}/ownerships","href":"/api-reference/synqownersv1ownersservice/listownerships"},{"title":"UpsertOwnership","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/owners/v1/{owner_id}/ownerships","href":"/api-reference/synqownersv1ownersservice/upsertownership"}]},{"group":"synq.platforms.v1.PlatformsService","pages":[{"title":"SetPlatformAuthentication","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/platforms/v1","href":"/api-reference/synqplatformsv1platformsservice/setplatformauthentication"}]},{"group":"synq.queries.v1.QueriesService","pages":[{"title":"DescribeResolverQl","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/queries/v1/describe-resolver-ql","href":"/api-reference/synqqueriesv1queriesservice/describeresolverql"},{"title":"ResolveQuery","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/queries/v1/resolve","href":"/api-reference/synqqueriesv1queriesservice/resolvequery"},{"title":"TranslateResolverQl","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/queries/v1/translate-resolver-ql","href":"/api-reference/synqqueriesv1queriesservice/translateresolverql"}]},{"group":"synq.queries.v1.NLQueryService","pages":[{"title":"GenerateQuery","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/queries/v1/generate","href":"/api-reference/synqqueriesv1nlqueryservice/generatequery"}]},{"group":"synq.recommendations.v1.RecommendationsService","pages":[{"title":"ListRecommendations","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/recommendations/v1","href":"/api-reference/synqrecommendationsv1recommendationsservice/listrecommendations"},{"title":"BatchGetRecommendations","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/recommendations/v1/by-id","href":"/api-reference/synqrecommendationsv1recommendationsservice/batchgetrecommendations"},{"title":"DismissRecommendation","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/recommendations/v1/{recommendation_id}/dismiss","href":"/api-reference/synqrecommendationsv1recommendationsservice/dismissrecommendation"},{"title":"IgnoreRecommendation","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/recommendations/v1/{recommendation_id}/ignore","href":"/api-reference/synqrecommendationsv1recommendationsservice/ignorerecommendation"},{"title":"RestoreRecommendation","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/recommendations/v1/{recommendation_id}/restore","href":"/api-reference/synqrecommendationsv1recommendationsservice/restorerecommendation"}]},{"group":"synq.agent.recon.v1.SuiteDeploymentService","pages":[{"title":"TriggerDeployment","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/recon/v1/deployments/trigger","href":"/api-reference/synqagentreconv1suitedeploymentservice/triggerdeployment"}]},{"group":"synq.entities.resolve.v1.IdentifierResolveService","pages":[{"title":"BatchResolveIdentifiers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/resolve/v1/by-id","href":"/api-reference/synqentitiesresolvev1identifierresolveservice/batchresolveidentifiers"}]},{"group":"synq.savedviews.v1.SavedViewsService","pages":[{"title":"Upsert","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/saved-views/v1","href":"/api-reference/synqsavedviewsv1savedviewsservice/upsert"},{"title":"BatchGet","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/saved-views/v1/batch-get","href":"/api-reference/synqsavedviewsv1savedviewsservice/batchget"},{"title":"Delete","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/saved-views/v1/delete","href":"/api-reference/synqsavedviewsv1savedviewsservice/delete"},{"title":"List","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/saved-views/v1/list","href":"/api-reference/synqsavedviewsv1savedviewsservice/list"},{"title":"SetPin","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/saved-views/v1/set-pin","href":"/api-reference/synqsavedviewsv1savedviewsservice/setpin"}]},{"group":"synq.schedule.v1.ScheduleService","pages":[{"title":"PreviewSchedules","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/schedule/v1/preview","href":"/api-reference/synqschedulev1scheduleservice/previewschedules"}]},{"group":"synq.entities.schemas.v1.SchemaMismatchesService","pages":[{"title":"BatchSchemaMismatches","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/schema-mismatches/v1","href":"/api-reference/synqentitiesschemasv1schemamismatchesservice/batchschemamismatches"}]},{"group":"synq.entities.schemas.v1.SchemasService","pages":[{"title":"GetSchema","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/schema/v1","href":"/api-reference/synqentitiesschemasv1schemasservice/getschema"}]},{"group":"synq.entities.sql_insights.v1.SqlInsightsService","pages":[{"title":"ListSqlConstructs","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/sql-insights/v1/constructs","href":"/api-reference/synqentitiessql_insightsv1sqlinsightsservice/listsqlconstructs"},{"title":"BatchSqlDetails","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/sql-insights/v1/details:batch","href":"/api-reference/synqentitiessql_insightsv1sqlinsightsservice/batchsqldetails"},{"title":"ListJoinPatterns","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/sql-insights/v1/join-patterns","href":"/api-reference/synqentitiessql_insightsv1sqlinsightsservice/listjoinpatterns"}]},{"group":"synq.agent.sre.v1.LlmService","pages":[{"title":"Evaluate","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/sre/llm/v1/evaluate","href":"/api-reference/synqagentsrev1llmservice/evaluate"}]},{"group":"synq.entities.status.v1.EntityIncidentsService","pages":[{"title":"BatchGetIncidents","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/status/v1/incidents/by-id","href":"/api-reference/synqentitiesstatusv1entityincidentsservice/batchgetincidents"}]},{"group":"synq.entities.status.v1.EntityIssuesService","pages":[{"title":"BatchGetIssuesStatus","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/status/v1/issues/by-id","href":"/api-reference/synqentitiesstatusv1entityissuesservice/batchgetissuesstatus"}]},{"group":"synq.agent.sre.v1.TriageService","pages":[{"title":"BatchLatestConclusions","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/triage/v1/conclusions","href":"/api-reference/synqagentsrev1triageservice/batchlatestconclusions"},{"title":"MarkFailed","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/triage/v1/failed","href":"/api-reference/synqagentsrev1triageservice/markfailed"},{"title":"MarkAsInProgress","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /api/triage/v1/in-progress","href":"/api-reference/synqagentsrev1triageservice/markasinprogress"},{"title":"BatchTriageState","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/triage/v1/states","href":"/api-reference/synqagentsrev1triageservice/batchtriagestate"},{"title":"ListTriageState","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/triage/v1/statuses","href":"/api-reference/synqagentsrev1triageservice/listtriagestate"},{"title":"Conclude","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/triage/v1/{session_id}/conclusion","href":"/api-reference/synqagentsrev1triageservice/conclude"},{"title":"RecordEvidence","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/triage/v1/{session_id}/evidence","href":"/api-reference/synqagentsrev1triageservice/recordevidence"}]},{"group":"synq.users.v1.UsersService","pages":[{"title":"ListUsers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/users/v1","href":"/api-reference/synqusersv1usersservice/listusers"},{"title":"GetUserAliases","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/users/v1/aliases","href":"/api-reference/synqusersv1usersservice/getuseraliases"},{"title":"UpsertUserAliases","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /api/users/v1/aliases","href":"/api-reference/synqusersv1usersservice/upsertuseraliases"},{"title":"DeleteUserAliases","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/users/v1/aliases/delete","href":"/api-reference/synqusersv1usersservice/deleteuseraliases"},{"title":"BatchGetUsers","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/users/v1/batch-get","href":"/api-reference/synqusersv1usersservice/batchgetusers"},{"title":"GetByAlias","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/users/v1/by-alias","href":"/api-reference/synqusersv1usersservice/getbyalias"},{"title":"GetByEmail","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/users/v1/by-email","href":"/api-reference/synqusersv1usersservice/getbyemail"},{"title":"GetUserIdentities","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api/users/v1/identities","href":"/api-reference/synqusersv1usersservice/getuseridentities"},{"title":"AddUserRole","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/users/v1/roles","href":"/api-reference/synqusersv1usersservice/adduserrole"},{"title":"RemoveUserRole","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api/users/v1/roles/remove","href":"/api-reference/synqusersv1usersservice/removeuserrole"}]}]},{"group":"gRPC API","pages":[{"title":"API","href":"/api-reference/api"},{"title":null,"href":"/api-reference/examples"}]},{"group":"Custom Integrations","pages":[{"title":"Custom Integrations","href":"/custom-integrations/overview"},{"title":"Modelling Your Tool","href":"/custom-integrations/modelling"},{"title":"Building an Integration","href":"/custom-integrations/building-an-integration"},{"title":"API Surface","href":"/custom-integrations/api-surface"},{"title":"Agent Workflow","href":"/custom-integrations/agent-workflow"}]},{"group":"Webhooks","pages":[{"title":"Using Webhooks","href":"/api-reference/webhook"},{"title":"Debugging Deliveries","href":"/api-reference/webhook-deliveries"}]}]}]}]},"basePath":"","title":"ValidateSuite - Coalesce Quality Documentation","buildId":"dpl_DeHjVRGfFnhYQwHnfC2pjeXXv8h9","deploymentId":"dpl_DeHjVRGfFnhYQwHnfC2pjeXXv8h9","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-CS552b7R.js","utils-DDTCYAF2.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-De8ttokP.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-DrwRDvAh.js","snippetPresets-DtAN0nWx.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","ApiExamples-D5rWArI6.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-O2i12wsz.js","shallow-DV8xABTt.js","getApiPlaygroundDisplay-DBZ0B5Jx.js","CodeSnippet-BVi0tPUX.js","CodeSnippets-CqASbIwY.js","Page-m07pfKpT.js","getPastedJson-DG9vsMS8.js","icon-CXzRSCr8.js","MethodPill-BdKVtEuX.js","DuplicateIcon-CZlmBrJI.js","createIcon-biFEUKPL.js","DynamicMarkdown-B54_zNBF.js","SectionHeading-DwwHK3Pt.js","axios-vUo_bRtp.js","Markdown-DfhCTwyA.js","clsx-xpJZXxdP.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-BTZUMDnx.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-DqdKa2R4.js"]}