kiri-cli 1.0.0b3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of kiri-cli might be problematic. Click here for more details.

Files changed (743) hide show
  1. kiri_adapters/__init__.py +193 -0
  2. kiri_adapters/backends/__init__.py +0 -0
  3. kiri_adapters/backends/databricks.manifest.yml +55 -0
  4. kiri_adapters/backends/databricks.py +2980 -0
  5. kiri_adapters/backends/fabric_dw.manifest.yml +17 -0
  6. kiri_adapters/backends/fabric_dw.py +307 -0
  7. kiri_adapters/backends/fabric_lakehouse.manifest.yml +19 -0
  8. kiri_adapters/backends/fabric_lakehouse.py +365 -0
  9. kiri_adapters/backends/iceberg.manifest.yml +17 -0
  10. kiri_adapters/backends/iceberg.py +451 -0
  11. kiri_adapters/backends/localduckdb.manifest.yml +43 -0
  12. kiri_adapters/backends/localduckdb.py +1295 -0
  13. kiri_adapters/backends/mssql.manifest.yml +17 -0
  14. kiri_adapters/backends/mssql.py +366 -0
  15. kiri_adapters/backends/postgres.manifest.yml +17 -0
  16. kiri_adapters/backends/postgres.py +434 -0
  17. kiri_adapters/backends/trino.manifest.yml +17 -0
  18. kiri_adapters/backends/trino.py +542 -0
  19. kiri_adapters/base.py +892 -0
  20. kiri_adapters/doctor_checks.py +81 -0
  21. kiri_adapters/dv_planner.py +1205 -0
  22. kiri_adapters/dv_planner_bridge.py +265 -0
  23. kiri_adapters/dv_planner_pit.py +265 -0
  24. kiri_adapters/dv_planner_ref.py +403 -0
  25. kiri_adapters/dv_planner_sat_variants.py +668 -0
  26. kiri_adapters/framework.py +112 -0
  27. kiri_adapters/incident/__init__.py +30 -0
  28. kiri_adapters/incident/_http.py +121 -0
  29. kiri_adapters/incident/base.py +89 -0
  30. kiri_adapters/incident/jira.py +365 -0
  31. kiri_adapters/incident/servicenow.py +314 -0
  32. kiri_adapters/incident/zendesk.py +285 -0
  33. kiri_adapters/manifest.py +466 -0
  34. kiri_adapters/orchestration/__init__.py +30 -0
  35. kiri_adapters/orchestration/airflow.py +117 -0
  36. kiri_adapters/orchestration/artifact_emitter.py +99 -0
  37. kiri_adapters/orchestration/autoloader_emitter.py +141 -0
  38. kiri_adapters/orchestration/azure_data_factory.py +137 -0
  39. kiri_adapters/orchestration/base.py +626 -0
  40. kiri_adapters/orchestration/databricks_workflows.py +1768 -0
  41. kiri_adapters/orchestration/k8s_cron.py +555 -0
  42. kiri_adapters/orchestration/lifecycle.py +222 -0
  43. kiri_adapters/orchestration/pipeline_compat.py +145 -0
  44. kiri_adapters/orchestration/runtime_python.py +188 -0
  45. kiri_adapters/paths.py +38 -0
  46. kiri_adapters/protocols/__init__.py +64 -0
  47. kiri_adapters/protocols/ai_service/__init__.py +7 -0
  48. kiri_adapters/protocols/ai_service/conformance.py +120 -0
  49. kiri_adapters/protocols/base.py +220 -0
  50. kiri_adapters/protocols/catalog/__init__.py +7 -0
  51. kiri_adapters/protocols/catalog/conformance.py +138 -0
  52. kiri_adapters/protocols/framework/__init__.py +7 -0
  53. kiri_adapters/protocols/framework/conformance.py +98 -0
  54. kiri_adapters/protocols/incident/__init__.py +7 -0
  55. kiri_adapters/protocols/incident/conformance.py +64 -0
  56. kiri_adapters/protocols/orchestration/__init__.py +7 -0
  57. kiri_adapters/protocols/orchestration/conformance.py +84 -0
  58. kiri_adapters/protocols/platform/__init__.py +7 -0
  59. kiri_adapters/protocols/platform/conformance.py +120 -0
  60. kiri_adapters/protocols/sql_dialect/__init__.py +7 -0
  61. kiri_adapters/protocols/sql_dialect/conformance.py +91 -0
  62. kiri_adapters/protocols/vault/__init__.py +7 -0
  63. kiri_adapters/protocols/vault/conformance.py +65 -0
  64. kiri_adapters/py.typed +0 -0
  65. kiri_adapters/registry.py +104 -0
  66. kiri_adapters/semantic/__init__.py +60 -0
  67. kiri_adapters/semantic/apply.py +274 -0
  68. kiri_adapters/semantic/base.py +530 -0
  69. kiri_adapters/semantic/cube.py +280 -0
  70. kiri_adapters/semantic/dbt_semantic.py +92 -0
  71. kiri_adapters/semantic/metric_views.py +249 -0
  72. kiri_adapters/semantic/metricflow.py +345 -0
  73. kiri_adapters/semantic/snowflake_views.py +75 -0
  74. kiri_adapters/sql_dialect.py +1592 -0
  75. kiri_adapters/tsql_to_spark.py +653 -0
  76. kiri_ai_gateway/__init__.py +147 -0
  77. kiri_ai_gateway/audit.py +334 -0
  78. kiri_ai_gateway/batch.py +293 -0
  79. kiri_ai_gateway/config.py +165 -0
  80. kiri_ai_gateway/gateway.py +642 -0
  81. kiri_ai_gateway/placeholder_guard.py +145 -0
  82. kiri_ai_gateway/prices/__init__.py +77 -0
  83. kiri_ai_gateway/prices/prices.yaml +64 -0
  84. kiri_ai_gateway/prompts/__init__.py +54 -0
  85. kiri_ai_gateway/prompts/airbyte_source_setup.yaml +212 -0
  86. kiri_ai_gateway/prompts/bdv_translation.yaml +90 -0
  87. kiri_ai_gateway/prompts/contract_draft_mvp.yaml +117 -0
  88. kiri_ai_gateway/prompts/describe_table.yaml +19 -0
  89. kiri_ai_gateway/prompts/design_gold_from_question.yaml +130 -0
  90. kiri_ai_gateway/prompts/detect_pii.yaml +59 -0
  91. kiri_ai_gateway/prompts/discover_classify_column.yaml +69 -0
  92. kiri_ai_gateway/prompts/discover_describe_table.yaml +61 -0
  93. kiri_ai_gateway/prompts/dv_quality_summary.yaml +36 -0
  94. kiri_ai_gateway/prompts/incident_assist.yaml +58 -0
  95. kiri_ai_gateway/prompts/infer_source_schema.yaml +31 -0
  96. kiri_ai_gateway/prompts/ingest_backend_chooser.yaml +116 -0
  97. kiri_ai_gateway/prompts/interactive_source_edit.yaml +94 -0
  98. kiri_ai_gateway/prompts/map_needed_entity_to_source.yaml +72 -0
  99. kiri_ai_gateway/prompts/meet_kiri.yaml +127 -0
  100. kiri_ai_gateway/prompts/native_source_setup.yaml +211 -0
  101. kiri_ai_gateway/prompts/source_grouping_reason.yaml +29 -0
  102. kiri_ai_gateway/prompts/suggest_attribute_classification.yaml +42 -0
  103. kiri_ai_gateway/prompts/suggest_data_tests.yaml +71 -0
  104. kiri_ai_gateway/prompts/suggest_gold_dimension.yaml +108 -0
  105. kiri_ai_gateway/prompts/suggest_gold_fact.yaml +107 -0
  106. kiri_ai_gateway/prompts/suggest_gold_model.yaml +70 -0
  107. kiri_ai_gateway/prompts/suggest_semantic_intent.yaml +91 -0
  108. kiri_ai_gateway/prompts/suggest_silver_model.yaml +140 -0
  109. kiri_ai_gateway/providers/__init__.py +7 -0
  110. kiri_ai_gateway/providers/anthropic_provider.py +26 -0
  111. kiri_ai_gateway/providers/gateway_provider.py +188 -0
  112. kiri_ai_gateway/providers/local_provider.py +177 -0
  113. kiri_ai_gateway/py.typed +0 -0
  114. kiri_ai_gateway/service.py +283 -0
  115. kiri_ai_gateway/transport.py +103 -0
  116. kiri_ai_gateway/transports/__init__.py +12 -0
  117. kiri_ai_gateway/transports/anthropic_transport.py +73 -0
  118. kiri_ai_gateway/transports/ollama_transport.py +82 -0
  119. kiri_ai_gateway/transports/openai_compatible_transport.py +125 -0
  120. kiri_ai_gateway/workspace_policy.py +52 -0
  121. kiri_catalog/__init__.py +199 -0
  122. kiri_catalog/annotation_plan.py +183 -0
  123. kiri_catalog/appearances.py +155 -0
  124. kiri_catalog/backends/__init__.py +79 -0
  125. kiri_catalog/backends/base.py +167 -0
  126. kiri_catalog/backends/memory.py +241 -0
  127. kiri_catalog/backends/postgres.py +497 -0
  128. kiri_catalog/backends/redacting.py +195 -0
  129. kiri_catalog/backends/sqlite.py +480 -0
  130. kiri_catalog/context.py +94 -0
  131. kiri_catalog/federation/__init__.py +114 -0
  132. kiri_catalog/federation/api.py +200 -0
  133. kiri_catalog/federation/cache.py +149 -0
  134. kiri_catalog/federation/emit.py +209 -0
  135. kiri_catalog/federation/fs_resolver.py +295 -0
  136. kiri_catalog/federation/http_resolver.py +486 -0
  137. kiri_catalog/federation/metrics.py +123 -0
  138. kiri_catalog/federation/release.py +342 -0
  139. kiri_catalog/federation/resolver.py +332 -0
  140. kiri_catalog/federation/schema.py +460 -0
  141. kiri_catalog/importer.py +668 -0
  142. kiri_catalog/lineage_drift.py +280 -0
  143. kiri_catalog/lineage_graph.py +176 -0
  144. kiri_catalog/lineage_graph_explain.py +96 -0
  145. kiri_catalog/lineage_graph_mermaid.py +230 -0
  146. kiri_catalog/observed_uc_lineage.py +216 -0
  147. kiri_catalog/pii_detect.py +176 -0
  148. kiri_catalog/push.py +122 -0
  149. kiri_catalog/py.typed +0 -0
  150. kiri_catalog/redact.py +101 -0
  151. kiri_catalog/review_actions.py +119 -0
  152. kiri_catalog/schema/__init__.py +70 -0
  153. kiri_catalog/schema/asset.py +142 -0
  154. kiri_catalog/schema/column.py +247 -0
  155. kiri_catalog/schema/enums.py +195 -0
  156. kiri_catalog/schema/job.py +51 -0
  157. kiri_catalog/schema/lineage.py +33 -0
  158. kiri_catalog/schema/policy.py +69 -0
  159. kiri_catalog/schema/primitives.py +90 -0
  160. kiri_catalog/schema/review_state.py +111 -0
  161. kiri_catalog/schema/urn.py +45 -0
  162. kiri_catalog/schema_discovery.py +160 -0
  163. kiri_catalog/sinks/__init__.py +64 -0
  164. kiri_catalog/sinks/base.py +178 -0
  165. kiri_catalog/sinks/horizon.py +195 -0
  166. kiri_catalog/sinks/purview.py +216 -0
  167. kiri_catalog/sinks/unity.py +352 -0
  168. kiri_catalog/sinks/unity_executor.py +543 -0
  169. kiri_catalog/sources/__init__.py +42 -0
  170. kiri_catalog/sources/base.py +104 -0
  171. kiri_catalog/sources/unity.py +465 -0
  172. kiri_catalog/steward_writeback.py +158 -0
  173. kiri_catalog/tag_sql.py +99 -0
  174. kiri_cli/LICENSE +105 -0
  175. kiri_cli/__init__.py +1 -0
  176. kiri_cli/_apply_cli.py +63 -0
  177. kiri_cli/_apply_reporter.py +38 -0
  178. kiri_cli/_closed_menu.py +36 -0
  179. kiri_cli/_fixture_option.py +18 -0
  180. kiri_cli/_layer_detect.py +158 -0
  181. kiri_cli/_project_option.py +79 -0
  182. kiri_cli/adapter_cmd.py +192 -0
  183. kiri_cli/ai_batch_cmd.py +258 -0
  184. kiri_cli/ai_cmd.py +352 -0
  185. kiri_cli/approve_cmd.py +659 -0
  186. kiri_cli/attr_cmd.py +575 -0
  187. kiri_cli/audit_cmd.py +348 -0
  188. kiri_cli/audit_correlate_cmd.py +648 -0
  189. kiri_cli/audit_join.py +437 -0
  190. kiri_cli/audit_join_cmd.py +160 -0
  191. kiri_cli/auto_cmd.py +97 -0
  192. kiri_cli/azure_cmd.py +243 -0
  193. kiri_cli/catalog.py +1293 -0
  194. kiri_cli/cli_reference_live.py +147 -0
  195. kiri_cli/compile_cmd.py +493 -0
  196. kiri_cli/compliance_cmd.py +221 -0
  197. kiri_cli/contract_approval_cmd.py +94 -0
  198. kiri_cli/contract_cmd.py +64 -0
  199. kiri_cli/contract_codeowners_cmd.py +162 -0
  200. kiri_cli/contract_diff.py +111 -0
  201. kiri_cli/contract_emit.py +90 -0
  202. kiri_cli/contract_export.py +192 -0
  203. kiri_cli/contract_lint.py +1505 -0
  204. kiri_cli/contract_merge_cmd.py +264 -0
  205. kiri_cli/contract_new.py +326 -0
  206. kiri_cli/contract_promote.py +216 -0
  207. kiri_cli/contract_scaffold_cmd.py +134 -0
  208. kiri_cli/contract_schema_export.py +69 -0
  209. kiri_cli/contract_show.py +150 -0
  210. kiri_cli/contract_stubs.py +60 -0
  211. kiri_cli/contract_sync_from_live.py +327 -0
  212. kiri_cli/contract_validate.py +154 -0
  213. kiri_cli/contract_verify_live.py +242 -0
  214. kiri_cli/cost_cmd.py +243 -0
  215. kiri_cli/databricks_health.py +1254 -0
  216. kiri_cli/databricks_setup_cmd.py +712 -0
  217. kiri_cli/discover_cmd.py +600 -0
  218. kiri_cli/docs_cmd.py +35 -0
  219. kiri_cli/doctor_cmd.py +145 -0
  220. kiri_cli/dv_cmd.py +814 -0
  221. kiri_cli/dv_conformance_cmd.py +154 -0
  222. kiri_cli/dv_install.py +493 -0
  223. kiri_cli/dv_migrate_cmd.py +183 -0
  224. kiri_cli/dv_test_cmd.py +175 -0
  225. kiri_cli/federation_cmd.py +315 -0
  226. kiri_cli/fk_cmd.py +160 -0
  227. kiri_cli/flows_cmd.py +910 -0
  228. kiri_cli/governance_cmd.py +358 -0
  229. kiri_cli/incident_api_cmd.py +180 -0
  230. kiri_cli/incident_cmd.py +410 -0
  231. kiri_cli/incident_setup_cmd.py +239 -0
  232. kiri_cli/ingest.py +427 -0
  233. kiri_cli/ingest_discover.py +480 -0
  234. kiri_cli/ingest_new_source.py +386 -0
  235. kiri_cli/intent_cmd.py +122 -0
  236. kiri_cli/invariants_cmd.py +118 -0
  237. kiri_cli/kiri_banner.py +161 -0
  238. kiri_cli/kpi_cmd.py +222 -0
  239. kiri_cli/layer_cmd.py +464 -0
  240. kiri_cli/lineage.py +601 -0
  241. kiri_cli/main.py +2472 -0
  242. kiri_cli/maturity_cmd.py +222 -0
  243. kiri_cli/migrate_cmd.py +1347 -0
  244. kiri_cli/onboard_cmd.py +223 -0
  245. kiri_cli/pack_cmd.py +496 -0
  246. kiri_cli/pipeline_cmd.py +127 -0
  247. kiri_cli/pre_classify_cmd.py +274 -0
  248. kiri_cli/project_cmd.py +592 -0
  249. kiri_cli/py.typed +0 -0
  250. kiri_cli/quality_cmd.py +295 -0
  251. kiri_cli/rbac.py +139 -0
  252. kiri_cli/rbac_cmd.py +291 -0
  253. kiri_cli/release.py +850 -0
  254. kiri_cli/release_semver.py +265 -0
  255. kiri_cli/repo_cmd.py +155 -0
  256. kiri_cli/retention_cmd.py +333 -0
  257. kiri_cli/sample_data/__init__.py +12 -0
  258. kiri_cli/sample_data/customers.contract.yml +47 -0
  259. kiri_cli/sample_data/customers.csv +25 -0
  260. kiri_cli/scaffold_cmd.py +721 -0
  261. kiri_cli/schema_cmd.py +185 -0
  262. kiri_cli/semantic_cmd.py +605 -0
  263. kiri_cli/silver_cmd.py +348 -0
  264. kiri_cli/skills_cmd.py +243 -0
  265. kiri_cli/skills_data/README.md +51 -0
  266. kiri_cli/skills_data/add-source/SKILL.md +116 -0
  267. kiri_cli/skills_data/azure-deploy/SKILL.md +261 -0
  268. kiri_cli/skills_data/azure-status/SKILL.md +111 -0
  269. kiri_cli/skills_data/compliance-check/SKILL.md +99 -0
  270. kiri_cli/skills_data/databricks-build-pipeline/SKILL.md +112 -0
  271. kiri_cli/skills_data/databricks-project-setup/SKILL.md +157 -0
  272. kiri_cli/skills_data/debug-apply/SKILL.md +186 -0
  273. kiri_cli/skills_data/draft-gold-model/SKILL.md +203 -0
  274. kiri_cli/skills_data/explain-kpi/SKILL.md +158 -0
  275. kiri_cli/skills_data/incident-coach/SKILL.md +135 -0
  276. kiri_cli/skills_data/incident-setup/SKILL.md +112 -0
  277. kiri_cli/skills_data/maturity-coach/SKILL.md +120 -0
  278. kiri_cli/skills_data/promote-contract/SKILL.md +91 -0
  279. kiri_cli/skills_data/review-attributes/SKILL.md +94 -0
  280. kiri_cli/sla_cmd.py +769 -0
  281. kiri_cli/source_cmd.py +909 -0
  282. kiri_cli/templates/__init__.py +6 -0
  283. kiri_cli/templates/dv4dbt_packages.yml.j2 +11 -0
  284. kiri_cli/upgrade_cmd.py +896 -0
  285. kiri_cli/use_cmd.py +120 -0
  286. kiri_cli/vault_cmd.py +241 -0
  287. kiri_cli/verify_generated.py +241 -0
  288. kiri_cli-1.0.0b3.dist-info/METADATA +212 -0
  289. kiri_cli-1.0.0b3.dist-info/RECORD +743 -0
  290. kiri_cli-1.0.0b3.dist-info/WHEEL +4 -0
  291. kiri_cli-1.0.0b3.dist-info/entry_points.txt +4 -0
  292. kiri_compliance/__init__.py +33 -0
  293. kiri_compliance/audit_coverage.py +354 -0
  294. kiri_compliance/controls.py +763 -0
  295. kiri_compliance/evidence.py +155 -0
  296. kiri_compliance/py.typed +0 -0
  297. kiri_compliance/quality_engine.py +246 -0
  298. kiri_compliance/renderer.py +195 -0
  299. kiri_compliance/report.py +44 -0
  300. kiri_compliance/schema.py +129 -0
  301. kiri_core/__init__.py +185 -0
  302. kiri_core/adapter_surfaces.py +149 -0
  303. kiri_core/ai_query_gate/__init__.py +92 -0
  304. kiri_core/ai_query_gate/audit.py +153 -0
  305. kiri_core/ai_query_gate/evaluator.py +484 -0
  306. kiri_core/ai_query_gate/models.py +162 -0
  307. kiri_core/ai_query_gate/parser.py +436 -0
  308. kiri_core/ai_query_gate/resolver.py +274 -0
  309. kiri_core/ai_query_gate/store.py +234 -0
  310. kiri_core/ai_query_gate/store_postgres.py +409 -0
  311. kiri_core/api_keys.py +243 -0
  312. kiri_core/apply/__init__.py +27 -0
  313. kiri_core/apply/conformance.py +99 -0
  314. kiri_core/apply/incident_router.py +176 -0
  315. kiri_core/apply/models.py +140 -0
  316. kiri_core/apply/reporter.py +46 -0
  317. kiri_core/apply/runner.py +3083 -0
  318. kiri_core/apply_log_store.py +155 -0
  319. kiri_core/approval_flow/__init__.py +133 -0
  320. kiri_core/approval_flow/integration.py +156 -0
  321. kiri_core/approval_flow/models.py +443 -0
  322. kiri_core/approval_flow/notifier.py +263 -0
  323. kiri_core/approval_flow/orchestrator.py +660 -0
  324. kiri_core/approval_flow/reconcile_signoff.py +53 -0
  325. kiri_core/approval_flow/store.py +220 -0
  326. kiri_core/approval_flow/store_jsonl.py +217 -0
  327. kiri_core/approval_flow/store_postgres.py +580 -0
  328. kiri_core/approval_policy.py +116 -0
  329. kiri_core/asgi_trace.py +160 -0
  330. kiri_core/compliance.py +802 -0
  331. kiri_core/cutover_approval.py +187 -0
  332. kiri_core/discovery/__init__.py +109 -0
  333. kiri_core/discovery/ai/__init__.py +37 -0
  334. kiri_core/discovery/ai/_payload.py +115 -0
  335. kiri_core/discovery/ai/budget.py +83 -0
  336. kiri_core/discovery/ai/classify.py +223 -0
  337. kiri_core/discovery/ai/describe.py +200 -0
  338. kiri_core/discovery/ai/errors.py +49 -0
  339. kiri_core/discovery/discover.py +648 -0
  340. kiri_core/discovery/heuristics/__init__.py +42 -0
  341. kiri_core/discovery/heuristics/classification.py +174 -0
  342. kiri_core/discovery/heuristics/medallion.py +157 -0
  343. kiri_core/discovery/heuristics/pii.py +92 -0
  344. kiri_core/discovery/introspector.py +636 -0
  345. kiri_core/discovery/introspector_databricks.py +396 -0
  346. kiri_core/discovery/introspector_postgres.py +394 -0
  347. kiri_core/discovery/introspector_snowflake.py +383 -0
  348. kiri_core/discovery/reporting/__init__.py +17 -0
  349. kiri_core/discovery/reporting/discovery_report.py +190 -0
  350. kiri_core/discovery/scaffold/__init__.py +41 -0
  351. kiri_core/discovery/scaffold/contract_writer.py +632 -0
  352. kiri_core/discovery/scaffold/provenance_overlay.py +143 -0
  353. kiri_core/discovery/scaffold/source_writer.py +211 -0
  354. kiri_core/discovery/scaffold/todo_marker.py +98 -0
  355. kiri_core/domain_policy.py +122 -0
  356. kiri_core/goal_coverage.py +82 -0
  357. kiri_core/gold_registry.py +211 -0
  358. kiri_core/health.py +192 -0
  359. kiri_core/incident.py +204 -0
  360. kiri_core/incident_builders.py +256 -0
  361. kiri_core/incident_log.py +418 -0
  362. kiri_core/intent/__init__.py +46 -0
  363. kiri_core/intent/agent_runner.py +82 -0
  364. kiri_core/intent/project_dv.py +261 -0
  365. kiri_core/intent/propose.py +132 -0
  366. kiri_core/intent/semantic_intent.py +446 -0
  367. kiri_core/invariants.py +301 -0
  368. kiri_core/kpi.py +373 -0
  369. kiri_core/latency.py +150 -0
  370. kiri_core/lifecycle/__init__.py +555 -0
  371. kiri_core/lifecycle/ai_index.py +453 -0
  372. kiri_core/lifecycle/auto_mode.py +172 -0
  373. kiri_core/lifecycle/bootstrap.py +316 -0
  374. kiri_core/lifecycle/cli_reference.py +1064 -0
  375. kiri_core/lifecycle/commit.py +258 -0
  376. kiri_core/lifecycle/compile_dispatch.py +296 -0
  377. kiri_core/lifecycle/compile_range.py +665 -0
  378. kiri_core/lifecycle/contract_inventory.py +354 -0
  379. kiri_core/lifecycle/contracts.py +250 -0
  380. kiri_core/lifecycle/doctor.py +412 -0
  381. kiri_core/lifecycle/git_remote.py +948 -0
  382. kiri_core/lifecycle/identity.py +147 -0
  383. kiri_core/lifecycle/ingestion_modes.py +215 -0
  384. kiri_core/lifecycle/layer_contract.py +452 -0
  385. kiri_core/lifecycle/layer_contract_migrate.py +969 -0
  386. kiri_core/lifecycle/layer_contract_parser.py +436 -0
  387. kiri_core/lifecycle/layer_contract_validator.py +2291 -0
  388. kiri_core/lifecycle/layout.py +298 -0
  389. kiri_core/lifecycle/onboarding.py +306 -0
  390. kiri_core/lifecycle/openlineage_emit.py +153 -0
  391. kiri_core/lifecycle/patch.py +231 -0
  392. kiri_core/lifecycle/plan.py +241 -0
  393. kiri_core/lifecycle/probe.py +204 -0
  394. kiri_core/lifecycle/project_context.py +334 -0
  395. kiri_core/lifecycle/project_status.py +532 -0
  396. kiri_core/lifecycle/scaffold.py +455 -0
  397. kiri_core/lifecycle/source_grouping.py +725 -0
  398. kiri_core/lifecycle/source_introspection.py +488 -0
  399. kiri_core/lifecycle/source_inventory.py +561 -0
  400. kiri_core/lifecycle/source_patch.py +353 -0
  401. kiri_core/lifecycle/sources.py +470 -0
  402. kiri_core/lifecycle/sync_from_live.py +727 -0
  403. kiri_core/lifecycle/validate.py +116 -0
  404. kiri_core/lifecycle/verify_annotations.py +391 -0
  405. kiri_core/lifecycle/verify_live.py +389 -0
  406. kiri_core/lifecycle/verify_metric_views.py +321 -0
  407. kiri_core/lifecycle/watermark.py +371 -0
  408. kiri_core/lifecycle/watermark_apply.py +656 -0
  409. kiri_core/lineage.py +418 -0
  410. kiri_core/loader.py +377 -0
  411. kiri_core/logging.py +374 -0
  412. kiri_core/maturity.py +592 -0
  413. kiri_core/migration_layer_policy.py +285 -0
  414. kiri_core/names.py +163 -0
  415. kiri_core/observed_lineage.py +62 -0
  416. kiri_core/odcs/__init__.py +15 -0
  417. kiri_core/otel_bootstrap.py +326 -0
  418. kiri_core/pipeline_ir.py +332 -0
  419. kiri_core/pipeline_loader.py +82 -0
  420. kiri_core/planning.py +110 -0
  421. kiri_core/project.py +1576 -0
  422. kiri_core/project_docs.py +199 -0
  423. kiri_core/py.typed +0 -0
  424. kiri_core/rate_limit.py +456 -0
  425. kiri_core/release_state/__init__.py +37 -0
  426. kiri_core/release_state/models.py +108 -0
  427. kiri_core/release_state/store.py +634 -0
  428. kiri_core/resilience/__init__.py +288 -0
  429. kiri_core/resilience/retry.py +173 -0
  430. kiri_core/runtime.py +40 -0
  431. kiri_core/schema/__init__.py +62 -0
  432. kiri_core/schema/column.py +140 -0
  433. kiri_core/schema/ingestion.py +665 -0
  434. kiri_core/schema/model.py +44 -0
  435. kiri_core/schema/reporting_goal.py +160 -0
  436. kiri_core/schema/source.py +188 -0
  437. kiri_core/silver/__init__.py +148 -0
  438. kiri_core/silver/apply_runner.py +830 -0
  439. kiri_core/silver/backfill.py +280 -0
  440. kiri_core/silver/dv_backend.py +426 -0
  441. kiri_core/silver/dv_graph.py +932 -0
  442. kiri_core/silver/dv_graph_mermaid.py +443 -0
  443. kiri_core/silver/dv_graph_payload.py +79 -0
  444. kiri_core/silver/dv_graph_views.py +416 -0
  445. kiri_core/silver/graph_projector.py +566 -0
  446. kiri_core/silver/hash_canonicaliser.py +172 -0
  447. kiri_core/silver/hash_policy.py +195 -0
  448. kiri_core/silver/load_ts_policy.py +202 -0
  449. kiri_core/silver/schema_evolution.py +410 -0
  450. kiri_core/silver/zone_rules.py +81 -0
  451. kiri_core/sizing.py +134 -0
  452. kiri_core/storage_paths.py +130 -0
  453. kiri_core/technique_validator.py +700 -0
  454. kiri_core/trace.py +409 -0
  455. kiri_core/types.py +41 -0
  456. kiri_core/urn.py +161 -0
  457. kiri_dbt_bridge/__init__.py +22 -0
  458. kiri_dbt_bridge/_schema_resolve.py +38 -0
  459. kiri_dbt_bridge/bridge.py +94 -0
  460. kiri_dbt_bridge/dbt.manifest.yml +26 -0
  461. kiri_dbt_bridge/dv4dbt/__init__.py +143 -0
  462. kiri_dbt_bridge/dv4dbt/backend.py +204 -0
  463. kiri_dbt_bridge/dv4dbt/bridge_generator.py +289 -0
  464. kiri_dbt_bridge/dv4dbt/compat.py +232 -0
  465. kiri_dbt_bridge/dv4dbt/hub_generator.py +282 -0
  466. kiri_dbt_bridge/dv4dbt/link_generator.py +306 -0
  467. kiri_dbt_bridge/dv4dbt/manifest.py +203 -0
  468. kiri_dbt_bridge/dv4dbt/pit_generator.py +318 -0
  469. kiri_dbt_bridge/dv4dbt/policy_translation.py +249 -0
  470. kiri_dbt_bridge/dv4dbt/project_writer.py +588 -0
  471. kiri_dbt_bridge/dv4dbt/ref_generator.py +404 -0
  472. kiri_dbt_bridge/dv4dbt/render.py +180 -0
  473. kiri_dbt_bridge/dv4dbt/sat_generator.py +480 -0
  474. kiri_dbt_bridge/dv4dbt/sat_variant_generator.py +529 -0
  475. kiri_dbt_bridge/dv4dbt/templates/__init__.py +16 -0
  476. kiri_dbt_bridge/dv4dbt/templates/bridge.sql.j2 +9 -0
  477. kiri_dbt_bridge/dv4dbt/templates/dbt_project.yml.j2 +37 -0
  478. kiri_dbt_bridge/dv4dbt/templates/hub.sql.j2 +9 -0
  479. kiri_dbt_bridge/dv4dbt/templates/link.sql.j2 +9 -0
  480. kiri_dbt_bridge/dv4dbt/templates/packages.yml.j2 +10 -0
  481. kiri_dbt_bridge/dv4dbt/templates/pit.sql.j2 +9 -0
  482. kiri_dbt_bridge/dv4dbt/templates/ref_historised.sql.j2 +9 -0
  483. kiri_dbt_bridge/dv4dbt/templates/ref_non_historised.sql.j2 +9 -0
  484. kiri_dbt_bridge/dv4dbt/templates/sat.sql.j2 +9 -0
  485. kiri_dbt_bridge/dv4dbt/templates/sat_effectivity.sql.j2 +9 -0
  486. kiri_dbt_bridge/dv4dbt/templates/sat_multi_active.sql.j2 +9 -0
  487. kiri_dbt_bridge/dv4dbt/templates/sat_non_historised.sql.j2 +9 -0
  488. kiri_dbt_bridge/dv4dbt/templates/sat_record_tracking.sql.j2 +9 -0
  489. kiri_dbt_bridge/dv4dbt/templates/sat_virtual_end_dated.sql.j2 +9 -0
  490. kiri_dbt_bridge/dv4dbt/templates/sources.yml.j2 +39 -0
  491. kiri_dbt_bridge/framework_adapter.py +310 -0
  492. kiri_dbt_bridge/generate.py +372 -0
  493. kiri_dbt_bridge/gold/__init__.py +21 -0
  494. kiri_dbt_bridge/gold/_sql_emit.py +128 -0
  495. kiri_dbt_bridge/gold/assemble.py +90 -0
  496. kiri_dbt_bridge/gold/canonical_columns.py +168 -0
  497. kiri_dbt_bridge/gold/computed_expressions.py +179 -0
  498. kiri_dbt_bridge/gold/dialects/__init__.py +69 -0
  499. kiri_dbt_bridge/gold/dialects/databricks.py +150 -0
  500. kiri_dbt_bridge/gold/dialects/duckdb.py +120 -0
  501. kiri_dbt_bridge/gold/dialects/trino.py +136 -0
  502. kiri_dbt_bridge/gold/dim_generator.py +688 -0
  503. kiri_dbt_bridge/gold/dimension_refs.py +255 -0
  504. kiri_dbt_bridge/gold/dispatch.py +69 -0
  505. kiri_dbt_bridge/gold/fact_generator.py +534 -0
  506. kiri_dbt_bridge/gold/flat_generator.py +144 -0
  507. kiri_dbt_bridge/gold/lineage.py +484 -0
  508. kiri_dbt_bridge/gold/localized_twins.py +218 -0
  509. kiri_dbt_bridge/gold/measures.py +49 -0
  510. kiri_dbt_bridge/gold/role_playing.py +75 -0
  511. kiri_dbt_bridge/gold/surrogate_key.py +114 -0
  512. kiri_dbt_bridge/macros/kiri_scd1_dim.sql +57 -0
  513. kiri_dbt_bridge/macros/kiri_scd2_dim.sql +188 -0
  514. kiri_dbt_bridge/macros/kiri_sha256.sql +32 -0
  515. kiri_dbt_bridge/macros/kiri_string_cast.sql +37 -0
  516. kiri_dbt_bridge/macros/kiri_surrogate_key.sql +43 -0
  517. kiri_dbt_bridge/profiles.py +162 -0
  518. kiri_dbt_bridge/py.typed +0 -0
  519. kiri_dbt_bridge/safe_ident.py +44 -0
  520. kiri_dbt_bridge/silver_conformance.py +188 -0
  521. kiri_dbt_bridge/silver_kimball/__init__.py +27 -0
  522. kiri_dbt_bridge/silver_kimball/assemble.py +174 -0
  523. kiri_dbt_bridge/silver_kimball/dim_generator.py +602 -0
  524. kiri_dbt_bridge/silver_kimball/dispatch.py +86 -0
  525. kiri_dbt_bridge/silver_kimball/fact_generator.py +320 -0
  526. kiri_dbt_bridge/silver_kimball/flat_generator.py +156 -0
  527. kiri_dbt_bridge/silver_kimball/lineage.py +464 -0
  528. kiri_dbt_bridge/silver_kimball/watermark_window.py +199 -0
  529. kiri_dbt_bridge/silver_kimball/zone.py +68 -0
  530. kiri_dbt_bridge/silver_scd2_curated/__init__.py +46 -0
  531. kiri_dbt_bridge/silver_scd2_curated/assemble.py +213 -0
  532. kiri_dbt_bridge/silver_scd2_curated/curated_generator.py +351 -0
  533. kiri_dbt_bridge/silver_scd2_curated/standardized_generator.py +261 -0
  534. kiri_dbt_bridge/silver_scd2_curated/standardized_plan.py +254 -0
  535. kiri_iceberg/__init__.py +11 -0
  536. kiri_iceberg/catalog.py +128 -0
  537. kiri_iceberg/profile.py +131 -0
  538. kiri_iceberg/py.typed +0 -0
  539. kiri_ingestion/__init__.py +63 -0
  540. kiri_ingestion/airbyte_client.py +428 -0
  541. kiri_ingestion/database_fetcher.py +224 -0
  542. kiri_ingestion/layout.py +71 -0
  543. kiri_ingestion/mssql_introspect.py +565 -0
  544. kiri_ingestion/py.typed +0 -0
  545. kiri_ingestion/rest_fetcher.py +472 -0
  546. kiri_ingestion/runner.py +341 -0
  547. kiri_ingestion/schema_drift.py +222 -0
  548. kiri_ingestion/storage.py +621 -0
  549. kiri_mcp/__init__.py +5 -0
  550. kiri_mcp/audit.py +99 -0
  551. kiri_mcp/audit_decorators.py +252 -0
  552. kiri_mcp/main.py +22 -0
  553. kiri_mcp/py.typed +0 -0
  554. kiri_mcp/rbac.py +110 -0
  555. kiri_mcp/server.py +766 -0
  556. kiri_mcp/skills.py +297 -0
  557. kiri_mcp/tools/__init__.py +70 -0
  558. kiri_mcp/tools/_shared.py +58 -0
  559. kiri_mcp/tools/adapter.py +150 -0
  560. kiri_mcp/tools/cli_reference.py +59 -0
  561. kiri_mcp/tools/compliance.py +119 -0
  562. kiri_mcp/tools/contract.py +374 -0
  563. kiri_mcp/tools/dv.py +62 -0
  564. kiri_mcp/tools/federation.py +152 -0
  565. kiri_mcp/tools/intent.py +71 -0
  566. kiri_mcp/tools/lineage.py +204 -0
  567. kiri_mcp/tools/lineage_drift.py +75 -0
  568. kiri_mcp/tools/plan.py +66 -0
  569. kiri_mcp/tools/project.py +311 -0
  570. kiri_migration/__init__.py +56 -0
  571. kiri_migration/name_preservation.py +271 -0
  572. kiri_migration/predeploy.py +311 -0
  573. kiri_migration/py.typed +0 -0
  574. kiri_migration/reconcile.py +1891 -0
  575. kiri_migration/scaffold/__init__.py +90 -0
  576. kiri_migration/scaffold/_audit_columns.py +74 -0
  577. kiri_migration/scaffold/_classify.py +100 -0
  578. kiri_migration/scaffold/_typemap.py +71 -0
  579. kiri_migration/scaffold/_yaml.py +33 -0
  580. kiri_migration/scaffold/bronze.py +279 -0
  581. kiri_migration/scaffold/compile_targets/__init__.py +271 -0
  582. kiri_migration/scaffold/compile_targets/_common.py +193 -0
  583. kiri_migration/scaffold/compile_targets/copy_into.py +33 -0
  584. kiri_migration/scaffold/compile_targets/dlt.py +125 -0
  585. kiri_migration/scaffold/compile_targets/dlt_with_append_flows.py +163 -0
  586. kiri_migration/scaffold/compile_targets/dlt_with_apply_changes.py +192 -0
  587. kiri_migration/scaffold/compile_targets/dlt_with_expectations.py +276 -0
  588. kiri_migration/scaffold/compile_targets/layer_dispatch.py +258 -0
  589. kiri_migration/scaffold/compile_targets/sql_full_snapshot.py +385 -0
  590. kiri_migration/scaffold/compile_targets/streaming_table.py +37 -0
  591. kiri_migration/scaffold/mart.py +234 -0
  592. kiri_migration/scaffold/plans/__init__.py +49 -0
  593. kiri_migration/scaffold/plans/_registry.py +308 -0
  594. kiri_migration/scaffold/plans/minimal.py +550 -0
  595. kiri_migration/scaffold/plans/plan_b_layer.py +640 -0
  596. kiri_migration/scaffold/silver_from_marts.py +256 -0
  597. kiri_migration/scaffold/silver_pattern.py +451 -0
  598. kiri_migration/sp_translator.py +398 -0
  599. kiri_odcs/LICENSE +204 -0
  600. kiri_odcs/__init__.py +234 -0
  601. kiri_odcs/ai_trust_tier.py +475 -0
  602. kiri_odcs/canonical.py +263 -0
  603. kiri_odcs/diff.py +63 -0
  604. kiri_odcs/errors.py +51 -0
  605. kiri_odcs/invariant_sql.py +136 -0
  606. kiri_odcs/kiri_bridge.py +71 -0
  607. kiri_odcs/kiri_ext.py +3166 -0
  608. kiri_odcs/kiri_fk.py +447 -0
  609. kiri_odcs/kiri_pit.py +121 -0
  610. kiri_odcs/kiri_ref.py +57 -0
  611. kiri_odcs/openlineage_adapter.py +105 -0
  612. kiri_odcs/parser.py +1213 -0
  613. kiri_odcs/pii_guardrails.py +159 -0
  614. kiri_odcs/py.typed +0 -0
  615. kiri_odcs/schema_export.py +223 -0
  616. kiri_openlineage/__init__.py +58 -0
  617. kiri_openlineage/builder.py +146 -0
  618. kiri_openlineage/cost.py +190 -0
  619. kiri_openlineage/emitter.py +165 -0
  620. kiri_openlineage/py.typed +0 -0
  621. kiri_openlineage/schema.py +121 -0
  622. kiri_packs/__init__.py +67 -0
  623. kiri_packs/installer.py +500 -0
  624. kiri_packs/manifest.py +134 -0
  625. kiri_packs/publisher.py +605 -0
  626. kiri_packs/py.typed +0 -0
  627. kiri_packs/validator.py +295 -0
  628. kiri_quality/__init__.py +108 -0
  629. kiri_quality/ai_audit_correlator.py +293 -0
  630. kiri_quality/ai_audit_correlator_apply.py +526 -0
  631. kiri_quality/conformance_evidence.py +272 -0
  632. kiri_quality/dbt_test_collector.py +214 -0
  633. kiri_quality/dq_codegen.py +300 -0
  634. kiri_quality/dv_checks.py +393 -0
  635. kiri_quality/dv_column_lineage.py +279 -0
  636. kiri_quality/dv_column_lineage_apply.py +856 -0
  637. kiri_quality/dv_conformance.py +841 -0
  638. kiri_quality/dv_fixture_runner.py +478 -0
  639. kiri_quality/dv_invariants.py +986 -0
  640. kiri_quality/dv_kiri.py +97 -0
  641. kiri_quality/dv_markdown.py +169 -0
  642. kiri_quality/dv_observed_uc_reader.py +187 -0
  643. kiri_quality/dv_runner.py +389 -0
  644. kiri_quality/evidence_status.py +337 -0
  645. kiri_quality/fk_checks.py +800 -0
  646. kiri_quality/fk_ddl.py +402 -0
  647. kiri_quality/fk_pit_contract.py +168 -0
  648. kiri_quality/fk_runner.py +950 -0
  649. kiri_quality/kernel.py +376 -0
  650. kiri_quality/pii.py +60 -0
  651. kiri_quality/pre_classify/__init__.py +55 -0
  652. kiri_quality/pre_classify/engine.py +346 -0
  653. kiri_quality/pre_classify/locale_packs/en.yaml +117 -0
  654. kiri_quality/pre_classify/locale_packs/sv.yaml +73 -0
  655. kiri_quality/pre_classify/merge.py +297 -0
  656. kiri_quality/pre_classify/model.py +163 -0
  657. kiri_quality/py.typed +0 -0
  658. kiri_quality/reject_lane.py +261 -0
  659. kiri_quality/rule_runner.py +565 -0
  660. kiri_quality/schema_evolution_check.py +88 -0
  661. kiri_quality/silver_quality.py +494 -0
  662. kiri_quality/silver_quality_markdown.py +187 -0
  663. kiri_quality/uc_security_compile.py +951 -0
  664. kiri_quality/uc_security_compile_apply.py +1186 -0
  665. kiri_rbac/__init__.py +87 -0
  666. kiri_rbac/access.py +371 -0
  667. kiri_rbac/loader.py +104 -0
  668. kiri_rbac/pr_gate.py +213 -0
  669. kiri_rbac/providers/__init__.py +29 -0
  670. kiri_rbac/providers/_jwt.py +121 -0
  671. kiri_rbac/providers/azure_ad.py +93 -0
  672. kiri_rbac/providers/base.py +107 -0
  673. kiri_rbac/providers/factory.py +48 -0
  674. kiri_rbac/providers/github.py +134 -0
  675. kiri_rbac/providers/oidc_generic.py +99 -0
  676. kiri_rbac/py.typed +0 -0
  677. kiri_rbac/resolver.py +118 -0
  678. kiri_rbac/schema.py +219 -0
  679. kiri_schema_registry/__init__.py +22 -0
  680. kiri_schema_registry/avro.py +127 -0
  681. kiri_schema_registry/base.py +71 -0
  682. kiri_schema_registry/confluent.py +184 -0
  683. kiri_schema_registry/glue.py +178 -0
  684. kiri_schema_registry/py.typed +0 -0
  685. kiri_slack_bot/__init__.py +24 -0
  686. kiri_slack_bot/handler.py +248 -0
  687. kiri_slack_bot/py.typed +0 -0
  688. kiri_slack_bot/queries.py +90 -0
  689. kiri_slack_bot/signature.py +94 -0
  690. kiri_vault/__init__.py +59 -0
  691. kiri_vault/audit.py +64 -0
  692. kiri_vault/aws_vault.py +123 -0
  693. kiri_vault/azure_vault.py +236 -0
  694. kiri_vault/boundaries.py +219 -0
  695. kiri_vault/client.py +54 -0
  696. kiri_vault/databricks_vault.py +292 -0
  697. kiri_vault/env_vault.py +77 -0
  698. kiri_vault/py.typed +0 -0
  699. kiri_vault/ref.py +84 -0
  700. kirimana_automation/__init__.py +0 -0
  701. kirimana_automation/business_calendar.py +179 -0
  702. kirimana_automation/dag_snapshot.py +252 -0
  703. kirimana_automation/db/__init__.py +5 -0
  704. kirimana_automation/db/migrate.py +571 -0
  705. kirimana_automation/db/migrations/0001_release_state.down.duckdb.sql +29 -0
  706. kirimana_automation/db/migrations/0001_release_state.down.postgres.sql +37 -0
  707. kirimana_automation/db/migrations/0001_release_state.duckdb.sql +170 -0
  708. kirimana_automation/db/migrations/0001_release_state.postgres.sql +176 -0
  709. kirimana_automation/db/migrations/0002_rate_limit_buckets.down.duckdb.sql +9 -0
  710. kirimana_automation/db/migrations/0002_rate_limit_buckets.down.postgres.sql +9 -0
  711. kirimana_automation/db/migrations/0002_rate_limit_buckets.duckdb.sql +14 -0
  712. kirimana_automation/db/migrations/0002_rate_limit_buckets.postgres.sql +18 -0
  713. kirimana_automation/db/migrations/0003_flow_runs.down.duckdb.sql +18 -0
  714. kirimana_automation/db/migrations/0003_flow_runs.down.postgres.sql +19 -0
  715. kirimana_automation/db/migrations/0003_flow_runs.duckdb.sql +85 -0
  716. kirimana_automation/db/migrations/0003_flow_runs.postgres.sql +102 -0
  717. kirimana_automation/db/migrations/0004_flow_dag_snapshots.down.duckdb.sql +11 -0
  718. kirimana_automation/db/migrations/0004_flow_dag_snapshots.down.postgres.sql +11 -0
  719. kirimana_automation/db/migrations/0004_flow_dag_snapshots.duckdb.sql +15 -0
  720. kirimana_automation/db/migrations/0004_flow_dag_snapshots.postgres.sql +31 -0
  721. kirimana_automation/db/migrations/0005_calendar_skip.down.duckdb.sql +109 -0
  722. kirimana_automation/db/migrations/0005_calendar_skip.down.postgres.sql +42 -0
  723. kirimana_automation/db/migrations/0005_calendar_skip.duckdb.sql +113 -0
  724. kirimana_automation/db/migrations/0005_calendar_skip.postgres.sql +42 -0
  725. kirimana_automation/db/migrations/0006_flow_apply_log.down.duckdb.sql +9 -0
  726. kirimana_automation/db/migrations/0006_flow_apply_log.down.postgres.sql +11 -0
  727. kirimana_automation/db/migrations/0006_flow_apply_log.duckdb.sql +45 -0
  728. kirimana_automation/db/migrations/0006_flow_apply_log.postgres.sql +49 -0
  729. kirimana_automation/db/migrations/0007_flow_task_error_redacted.down.duckdb.sql +14 -0
  730. kirimana_automation/db/migrations/0007_flow_task_error_redacted.down.postgres.sql +2 -0
  731. kirimana_automation/db/migrations/0007_flow_task_error_redacted.duckdb.sql +7 -0
  732. kirimana_automation/db/migrations/0007_flow_task_error_redacted.postgres.sql +11 -0
  733. kirimana_automation/db/migrations/README.md +84 -0
  734. kirimana_automation/flow_loader.py +220 -0
  735. kirimana_automation/freeze.py +133 -0
  736. kirimana_automation/kiri_recommender.py +313 -0
  737. kirimana_automation/main.py +195 -0
  738. kirimana_automation/py.typed +0 -0
  739. kirimana_automation/run_history.py +593 -0
  740. kirimana_automation/run_history_analysis.py +607 -0
  741. kirimana_automation/schedule.py +343 -0
  742. kirimana_automation/schedule_validator.py +572 -0
  743. kirimana_automation/workflow_compiler.py +1288 -0
@@ -0,0 +1,320 @@
1
+ """Silver-Kimball FACT generator (ADR 0099).
2
+
3
+ Mirrors :mod:`kiri_dbt_bridge.gold.fact_generator` with two differences:
4
+
5
+ - reads ``contract.kiri.silver`` instead of ``contract.kiri.gold``;
6
+ - pulls FROM bronze via :func:`silver_kimball.lineage.from_clause`.
7
+
8
+ Silver-Kimball facts have **no** ``dimension_refs`` — at the
9
+ conformed-master layer the silver facts ARE the atomic facts, joining
10
+ silver dims by their PK directly. There is no separate dim-FK
11
+ validation step; the projection emits each silver column from its
12
+ own lineage and authors point FK columns at the right bronze PK.
13
+
14
+ Lineage-driven projection emits each silver column as
15
+ ``<bronze_alias>.<bronze_col> AS <silver_col>``.
16
+
17
+ Every silver-fact column must declare a non-empty
18
+ ``kiri.lineage.from_columns``. Empty-lineage on facts means we'd
19
+ silently drop the column from emission — fail closed.
20
+
21
+ Measure validation walks lineage to the bronze source and rejects
22
+ SUM / AVG over non-numeric bronze columns.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ from pathlib import Path
28
+ from typing import TYPE_CHECKING
29
+
30
+ from kiri_odcs.kiri_ext import GoldKind, MeasureAggregation
31
+
32
+ from kiri_dbt_bridge.silver_kimball.lineage import (
33
+ SilverLineagePlan,
34
+ build_silver_lineage_plan,
35
+ from_clause,
36
+ parse_bronze_lineage,
37
+ render_property_projection,
38
+ )
39
+ from kiri_dbt_bridge.silver_kimball.watermark_window import (
40
+ render_pre_hook,
41
+ render_window_predicate,
42
+ )
43
+ from kiri_dbt_bridge.silver_kimball.zone import resolve_silver_schema
44
+
45
+ if TYPE_CHECKING:
46
+ from kiri_core import CanonicalContract, Project
47
+ from kiri_core.lifecycle import WatermarkWindow
48
+
49
+ from kiri_dbt_bridge.gold.dialects import GoldDialect
50
+
51
+
52
+ _NUMERIC_LOGICAL_TYPES = {"integer", "long", "number", "decimal", "float", "double"}
53
+ _NUMERIC_REQUIRED_AGGS = {MeasureAggregation.SUM, MeasureAggregation.AVG}
54
+
55
+
56
+ def _check_all_columns_have_lineage(contract: CanonicalContract) -> None:
57
+ """Raise if any silver-fact column has no or empty lineage."""
58
+ schema = contract.primary_schema
59
+ if schema is None:
60
+ raise ValueError(f"Silver-Kimball fact {contract.contract.name!r} has no schema.")
61
+ missing: list[str] = []
62
+ empty: list[str] = []
63
+ for prop in schema.properties:
64
+ key = f"{schema.name}.{prop.name}"
65
+ col_meta = contract.kiri.properties.get(key)
66
+ if col_meta is None or col_meta.lineage is None:
67
+ missing.append(prop.name)
68
+ continue
69
+ if not col_meta.lineage.from_columns:
70
+ empty.append(prop.name)
71
+ if missing:
72
+ raise ValueError(
73
+ f"Silver-Kimball fact {contract.contract.name!r}: column(s) "
74
+ f"{missing} have no kiri.lineage.from_columns declared. Every "
75
+ "fact column must declare lineage; empty list ('originates "
76
+ "here') is only valid on dimensions."
77
+ )
78
+ if empty:
79
+ raise ValueError(
80
+ f"Silver-Kimball fact {contract.contract.name!r}: column(s) "
81
+ f"{empty} have empty kiri.lineage.from_columns. Facts have no "
82
+ "'originates here' columns — declare the bronze source for "
83
+ "every column or remove it from the schema."
84
+ )
85
+
86
+
87
+ def _validate_measures(contract: CanonicalContract, project: Project) -> None:
88
+ """Reject measures whose lineage-resolved bronze source type can't
89
+ sustain the declared aggregation.
90
+ """
91
+ schema = contract.primary_schema
92
+ if schema is None:
93
+ return
94
+ bronze_by_name: dict[str, CanonicalContract] = {c.contract.name: c for c in project.contracts}
95
+ for measure in contract.kiri.silver.measures:
96
+ if measure.aggregation not in _NUMERIC_REQUIRED_AGGS:
97
+ continue
98
+ key = f"{schema.name}.{measure.column}"
99
+ col_meta = contract.kiri.properties.get(key)
100
+ if col_meta is None or col_meta.lineage is None or not col_meta.lineage.from_columns:
101
+ continue
102
+ first_urn = col_meta.lineage.from_columns[0]
103
+ try:
104
+ ref = parse_bronze_lineage(first_urn)
105
+ except ValueError:
106
+ continue
107
+ bronze = bronze_by_name.get(ref.contract_name)
108
+ if bronze is None or bronze.primary_schema is None:
109
+ continue
110
+ bronze_col_type: str | None = None
111
+ for prop in bronze.primary_schema.properties:
112
+ if prop.name == ref.column:
113
+ bronze_col_type = (prop.logical_type or "").lower()
114
+ break
115
+ if bronze_col_type and bronze_col_type not in _NUMERIC_LOGICAL_TYPES:
116
+ raise ValueError(
117
+ f"Silver-Kimball fact {contract.contract.name!r}: measure "
118
+ f"{measure.name!r} declares aggregation "
119
+ f"{measure.aggregation.value!r} over silver column "
120
+ f"{measure.column!r}, whose lineage resolves to bronze "
121
+ f"{ref.contract_name}::{ref.column} with "
122
+ f"logicalType={bronze_col_type!r}. "
123
+ f"{measure.aggregation.value.upper()} requires a numeric "
124
+ f"bronze source ({sorted(_NUMERIC_LOGICAL_TYPES)}). "
125
+ "Either change the aggregation (e.g. COUNT) or "
126
+ "pre-compute a numeric column in bronze."
127
+ )
128
+
129
+
130
+ def generate_fact_model(
131
+ contract: CanonicalContract,
132
+ project: Project,
133
+ dialect: GoldDialect,
134
+ window: WatermarkWindow | None = None,
135
+ ) -> str:
136
+ """Render the full ``models/silver/<fact_name>.sql`` body.
137
+
138
+ Backwards compatible (ADR 0080 "backwards compat"): ``window=None`` — or a
139
+ contract that does not declare ``kiri.watermark`` — yields the byte-identical
140
+ ``materialized='table'`` full-build SQL this generator always produced. When a
141
+ ``window`` is supplied AND the contract declares ``kiri.watermark``, the model
142
+ becomes ``materialized='incremental'`` with ``incremental_strategy='append'``
143
+ (a fact is an append of new fact rows) paired with a ``pre_hook`` window-delete
144
+ — EXACTLY the flat shape (ADR 0080 §3/§4 Slice D). A fact carries no dbt
145
+ ``unique_key`` (its grain is not a merge key), and in the installed
146
+ dbt-duckdb/dbt-databricks macros a keyless ``delete+insert`` does NOT delete,
147
+ so the keyless ``append`` + a ``pre_hook`` that clears exactly the
148
+ ``(lower, upper]`` window before the append is the portable idempotent path
149
+ (see :func:`kiri_dbt_bridge.silver_kimball.watermark_window.render_pre_hook`).
150
+
151
+ Load-bearing (ADR 0080 §4): you must NOT add a bare source-window WHERE to the
152
+ current full-rebuild ``materialized='table'`` model — that would replace the
153
+ table with only the windowed rows (data loss). The model becomes genuinely
154
+ incremental; the source WHERE is guarded by ``{% if is_incremental() %}`` so
155
+ the first run builds full up to ``upper``, and the post-success advance reads
156
+ ``max(<field>)`` over the materialised SILVER OUTPUT — so the watermark field
157
+ MUST be a projected output column (:func:`render_window_predicate` fails closed
158
+ when it is not).
159
+ """
160
+ silver = contract.kiri.silver
161
+ if silver.kind not in (
162
+ GoldKind.FACT,
163
+ GoldKind.FACTLESS_FACT,
164
+ GoldKind.SNAPSHOT_FACT,
165
+ GoldKind.ACCUMULATING_SNAPSHOT,
166
+ ):
167
+ raise ValueError(
168
+ f"generate_fact_model called with kind={silver.kind!r}; "
169
+ "this generator handles the four FACT-family kinds: "
170
+ "fact / factless_fact / snapshot_fact / accumulating_snapshot."
171
+ )
172
+
173
+ if not silver.grain:
174
+ raise ValueError(
175
+ f"Silver-Kimball fact {contract.contract.name!r} has no grain — "
176
+ "set kiri.silver.grain to the column(s) that identify a row."
177
+ )
178
+
179
+ coarser_grain = len(silver.grain) > 1
180
+
181
+ _check_all_columns_have_lineage(contract)
182
+ _validate_measures(contract, project)
183
+
184
+ plan = build_silver_lineage_plan(contract, project)
185
+ schema = resolve_silver_schema(contract, project)
186
+
187
+ # Incremental ONLY when a window is supplied AND the contract declares a
188
+ # watermark. Otherwise the byte-identical full-table build (backwards compat).
189
+ incremental = window is not None and contract.kiri.watermark is not None
190
+
191
+ if incremental:
192
+ assert window is not None # narrowed by `incremental`
193
+ pre_hook = render_pre_hook(contract, window, dialect)
194
+ config = (
195
+ f"{{{{ config(materialized='incremental', incremental_strategy='append'"
196
+ f"{pre_hook}, "
197
+ f"schema='{schema}') }}}}\n"
198
+ f"-- Generated from silver-Kimball contract {contract.contract.name!r} "
199
+ f"({silver.kind.value}, grain={silver.grain}, incremental over a "
200
+ f"store-derived watermark window, ADR 0080 §3/§4). append + pre_hook "
201
+ f"window-delete (idempotent re-run: the pre_hook deletes exactly the "
202
+ f"(lower, upper] window from this before the append — no duplicate "
203
+ f"facts; a keyless delete+insert would NOT delete). Target-native SQL "
204
+ f"emitted via the {dialect.name!r} dialect helper (ADR 0099).\n"
205
+ )
206
+ predicate = render_window_predicate(contract, window, dialect, plan, shape="fact")
207
+ else:
208
+ config = (
209
+ f"{{{{ config(materialized='table', schema='{schema}') }}}}\n"
210
+ f"-- Generated from silver-Kimball contract {contract.contract.name!r} "
211
+ f"({silver.kind.value}, grain={silver.grain}). Target-native SQL "
212
+ f"emitted via the {dialect.name!r} dialect helper (ADR 0099).\n"
213
+ )
214
+ predicate = ""
215
+
216
+ body = (
217
+ _coarser_grain_sql(contract, plan, predicate)
218
+ if coarser_grain
219
+ else _row_grain_sql(contract, plan, predicate)
220
+ )
221
+
222
+ return config + "\n" + body
223
+
224
+
225
+ def _row_grain_sql(contract: CanonicalContract, plan: SilverLineagePlan, predicate: str) -> str:
226
+ """Row-grain fact: plain SELECT projection + FROM/JOIN [+ window WHERE]."""
227
+ projection_lines = [
228
+ render_property_projection(contract, silver_col, ref, plan)
229
+ for silver_col, ref in plan.column_sources
230
+ ]
231
+ if not projection_lines:
232
+ raise ValueError("Row-grain silver fact produced no projection lines.")
233
+ body = "select\n " + ",\n ".join(projection_lines) + "\n" + from_clause(plan) + "\n"
234
+ if predicate:
235
+ body += predicate + "\n"
236
+ return body
237
+
238
+
239
+ def _coarser_grain_sql(contract: CanonicalContract, plan: SilverLineagePlan, predicate: str) -> str:
240
+ """Coarser-grain fact: GROUP BY the grain columns + aggregate measures.
241
+
242
+ Each grain column is projected as ``<alias>.<bronze_col> AS <grain_col>``;
243
+ each declared ``kiri.silver.measures`` entry emits
244
+ ``<AGG>(<alias>.<bronze_col>) AS <measure_name>``; every OTHER
245
+ silver column (degenerate dimensions, FK columns reached via the
246
+ grain) is projected raw — they must be functionally determined by
247
+ the grain (Kimball invariant).
248
+ """
249
+ silver = contract.kiri.silver
250
+ grain_set = set(silver.grain)
251
+ measure_source_cols = {m.column for m in silver.measures}
252
+
253
+ sources: dict[str, object] = dict(plan.column_sources)
254
+ aliases = plan.aliases
255
+
256
+ select_lines: list[str] = []
257
+ group_by_lines: list[str] = []
258
+
259
+ for grain_col in silver.grain:
260
+ ref = sources.get(grain_col)
261
+ if ref is None:
262
+ raise ValueError(
263
+ f"Silver-Kimball fact {contract.contract.name!r}: grain "
264
+ f"column {grain_col!r} has no lineage source."
265
+ )
266
+ qualified = f"{aliases[ref.contract_name]}.{ref.column}" # type: ignore[attr-defined]
267
+ select_lines.append(f"{qualified} as {grain_col}")
268
+ group_by_lines.append(qualified)
269
+
270
+ for measure in silver.measures:
271
+ m_ref = sources.get(measure.column)
272
+ if m_ref is None:
273
+ raise ValueError(
274
+ f"Silver-Kimball fact {contract.contract.name!r}: measure "
275
+ f"{measure.name!r} references column "
276
+ f"{measure.column!r} which has no lineage source."
277
+ )
278
+ bronze_alias = aliases[m_ref.contract_name] # type: ignore[attr-defined]
279
+ bronze_col = m_ref.column # type: ignore[attr-defined]
280
+ operand = f"{bronze_alias}.{bronze_col}"
281
+ agg = measure.aggregation.value.upper()
282
+ expr = f"COUNT(DISTINCT {operand})" if agg == "COUNT_DISTINCT" else f"{agg}({operand})"
283
+ select_lines.append(f"{expr} as {measure.name}")
284
+
285
+ for silver_col, ref in plan.column_sources:
286
+ if silver_col in grain_set or silver_col in measure_source_cols:
287
+ continue
288
+ qualified_ref = f"{aliases[ref.contract_name]}.{ref.column}"
289
+ select_lines.append(f"{qualified_ref} as {silver_col}")
290
+ group_by_lines.append(qualified_ref)
291
+
292
+ # The store-derived window WHERE (guarded by {% if is_incremental() %})
293
+ # filters the bronze SOURCE rows BEFORE the aggregation, so it slots between
294
+ # FROM and GROUP BY. Empty (no window / non-incremental) → unchanged SQL.
295
+ where = f"{predicate}\n" if predicate else ""
296
+ return (
297
+ "select\n "
298
+ + ",\n ".join(select_lines)
299
+ + "\n"
300
+ + from_clause(plan)
301
+ + "\n"
302
+ + where
303
+ + "group by "
304
+ + ", ".join(group_by_lines)
305
+ + "\n"
306
+ )
307
+
308
+
309
+ def write_fact_model(
310
+ contract: CanonicalContract,
311
+ project: Project,
312
+ dialect: GoldDialect,
313
+ output_dir: Path,
314
+ window: WatermarkWindow | None = None,
315
+ ) -> Path:
316
+ """Write the model file and return its path."""
317
+ output_dir.mkdir(parents=True, exist_ok=True)
318
+ path = output_dir / f"{contract.contract.name}.sql"
319
+ path.write_text(generate_fact_model(contract, project, dialect, window), encoding="utf-8")
320
+ return path
@@ -0,0 +1,156 @@
1
+ """Silver-Kimball FLAT generator (ADR 0099).
2
+
3
+ Explicit opt-out from Kimball star-schema modelling
4
+ (``kiri.silver.kind=flat``). The silver contract just projects columns
5
+ from one or more bronze sources — no grain, no business keys, no
6
+ SCD semantics. lint's dimensional rules skip flat contracts.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from pathlib import Path
12
+ from typing import TYPE_CHECKING
13
+
14
+ from kiri_odcs.kiri_ext import GoldKind
15
+
16
+ from kiri_dbt_bridge.silver_kimball.lineage import (
17
+ build_silver_lineage_plan,
18
+ from_clause,
19
+ render_property_projection,
20
+ )
21
+ from kiri_dbt_bridge.silver_kimball.watermark_window import (
22
+ render_pre_hook,
23
+ render_window_predicate,
24
+ )
25
+ from kiri_dbt_bridge.silver_kimball.zone import resolve_silver_schema
26
+
27
+ if TYPE_CHECKING:
28
+ from kiri_core import CanonicalContract, Project
29
+ from kiri_core.lifecycle import WatermarkWindow
30
+
31
+ from kiri_dbt_bridge.gold.dialects import GoldDialect
32
+
33
+
34
+ def _check_all_columns_have_lineage(contract: CanonicalContract) -> None:
35
+ """Same fail-closed check as fact_generator: every column must
36
+ declare a non-empty lineage."""
37
+ schema = contract.primary_schema
38
+ if schema is None:
39
+ raise ValueError(f"Silver-Kimball flat {contract.contract.name!r} has no schema.")
40
+ missing: list[str] = []
41
+ empty: list[str] = []
42
+ for prop in schema.properties:
43
+ key = f"{schema.name}.{prop.name}"
44
+ col_meta = contract.kiri.properties.get(key)
45
+ if col_meta is None or col_meta.lineage is None:
46
+ missing.append(prop.name)
47
+ continue
48
+ if not col_meta.lineage.from_columns:
49
+ empty.append(prop.name)
50
+ if missing:
51
+ raise ValueError(
52
+ f"Silver-Kimball flat {contract.contract.name!r}: column(s) "
53
+ f"{missing} have no kiri.lineage.from_columns declared."
54
+ )
55
+ if empty:
56
+ raise ValueError(
57
+ f"Silver-Kimball flat {contract.contract.name!r}: column(s) "
58
+ f"{empty} have empty kiri.lineage.from_columns — flat tables "
59
+ "have no 'originates here' columns."
60
+ )
61
+
62
+
63
+ def generate_flat_model(
64
+ contract: CanonicalContract,
65
+ project: Project,
66
+ dialect: GoldDialect,
67
+ window: WatermarkWindow | None = None,
68
+ ) -> str:
69
+ """Render the flat silver dbt model SQL.
70
+
71
+ Backwards compatible (ADR 0080 "backwards compat"): ``window=None`` — or a
72
+ contract that does not declare ``kiri.watermark`` — yields the byte-identical
73
+ ``materialized='table'`` full-build SQL this generator always produced. When a
74
+ ``window`` is supplied AND the contract declares ``kiri.watermark``, the model
75
+ becomes ``materialized='incremental'`` with the store-derived window injected
76
+ into a ``{% if is_incremental() %}`` WHERE predicate (ADR 0080 §3/§4, Slice B).
77
+
78
+ Incremental strategy is ``append`` paired with a ``pre_hook`` window-delete
79
+ (NOT a keyless ``delete+insert``). Flat silver carries no business/unique key
80
+ (the validator forbids ``business_keys`` on ``kind=flat``), and in the
81
+ installed dbt-duckdb/dbt-databricks macros ``delete+insert``/``merge`` only
82
+ delete when a ``unique_key`` is set — a keyless ``delete+insert`` silently
83
+ degrades to a plain append → duplicates on a held-on-failure re-run or a
84
+ ``--reset`` backfill, violating ADR 0017's safe-re-run guarantee. Instead the
85
+ model appends and a ``pre_hook`` unconditionally deletes exactly the
86
+ ``(lower, upper]`` window from ``{{ this }}`` (guarded by
87
+ ``{% if is_incremental() %}``) before the append, so a re-run is a true
88
+ delete-then-reinsert (no duplicates). ``pre_hook`` + ``append`` behave
89
+ identically on dbt-databricks and dbt-duckdb (ADR 0130); see
90
+ :func:`kiri_dbt_bridge.silver_kimball.watermark_window.render_pre_hook`.
91
+ """
92
+ silver = contract.kiri.silver
93
+ if silver.kind is not GoldKind.FLAT:
94
+ raise ValueError(
95
+ f"generate_flat_model called with kind={silver.kind!r}; "
96
+ "this generator only handles kiri.silver.kind=flat."
97
+ )
98
+ _check_all_columns_have_lineage(contract)
99
+ plan = build_silver_lineage_plan(contract, project)
100
+ schema = resolve_silver_schema(contract, project)
101
+
102
+ projection_lines = [
103
+ render_property_projection(contract, silver_col, ref, plan)
104
+ for silver_col, ref in plan.column_sources
105
+ ]
106
+ if not projection_lines:
107
+ raise ValueError(
108
+ f"Silver-Kimball flat {contract.contract.name!r} produced no projection lines."
109
+ )
110
+
111
+ # Incremental ONLY when a window is supplied AND the contract declares a
112
+ # watermark. Otherwise the byte-identical full-table build (backwards compat).
113
+ incremental = window is not None and contract.kiri.watermark is not None
114
+
115
+ if incremental:
116
+ assert window is not None # narrowed by `incremental`
117
+ pre_hook = render_pre_hook(contract, window, dialect)
118
+ config = (
119
+ f"{{{{ config(materialized='incremental', incremental_strategy='append'"
120
+ f"{pre_hook}, "
121
+ f"schema='{schema}') }}}}\n"
122
+ f"-- Generated from silver-Kimball contract {contract.contract.name!r} "
123
+ f"(flat — Kimball opt-out, incremental over a store-derived watermark "
124
+ f"window, ADR 0080 §3/§4). append + pre_hook window-delete (idempotent "
125
+ f"re-run: the pre_hook deletes exactly the (lower, upper] window from "
126
+ f"this before the append — no duplicate append; a keyless delete+insert "
127
+ f"would NOT delete). Target-native SQL via the "
128
+ f"{dialect.name!r} dialect helper (ADR 0099).\n"
129
+ )
130
+ predicate = render_window_predicate(contract, window, dialect, plan, shape="flat")
131
+ else:
132
+ config = (
133
+ f"{{{{ config(materialized='table', schema='{schema}') }}}}\n"
134
+ f"-- Generated from silver-Kimball contract {contract.contract.name!r} "
135
+ f"(flat — Kimball opt-out). Target-native SQL via the "
136
+ f"{dialect.name!r} dialect helper (ADR 0099).\n"
137
+ )
138
+ predicate = ""
139
+
140
+ body = "select\n " + ",\n ".join(projection_lines) + "\n" + from_clause(plan) + "\n"
141
+ if predicate:
142
+ body += predicate + "\n"
143
+ return config + "\n" + body
144
+
145
+
146
+ def write_flat_model(
147
+ contract: CanonicalContract,
148
+ project: Project,
149
+ dialect: GoldDialect,
150
+ output_dir: Path,
151
+ window: WatermarkWindow | None = None,
152
+ ) -> Path:
153
+ output_dir.mkdir(parents=True, exist_ok=True)
154
+ path = output_dir / f"{contract.contract.name}.sql"
155
+ path.write_text(generate_flat_model(contract, project, dialect, window), encoding="utf-8")
156
+ return path