typedef-data-intelligence 0.40.0__tar.gz → 0.41.0__tar.gz

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.
Files changed (278) hide show
  1. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/CHANGELOG.md +7 -0
  2. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/PKG-INFO +1 -1
  3. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/pyproject.toml +1 -1
  4. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_sync.py +33 -24
  5. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_setup.py +69 -0
  6. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_sync.py +365 -4
  7. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/.dockerignore +0 -0
  8. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/.env.example +0 -0
  9. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/.gitignore +0 -0
  10. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/.justfile_help.txt +0 -0
  11. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/Dockerfile +0 -0
  12. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/Dockerfile.dev +0 -0
  13. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/Justfile +0 -0
  14. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/README.pypi.md +0 -0
  15. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/config.api.yml +0 -0
  16. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/config.cli.yml +0 -0
  17. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/config.desktop.yml +0 -0
  18. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/config.ingest.unified.yml +0 -0
  19. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/config.ingest.yml +0 -0
  20. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docker-entrypoint.dev.sh +0 -0
  21. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/LINEAR_TICKETING_BACKEND.md +0 -0
  22. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/architecture/BUSINESS_CONCEPT_INDEX.md +0 -0
  23. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/architecture/CLUSTERING_ALGORITHM_DECISION.md +0 -0
  24. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/architecture/GENERIC_REPORT_SCHEMA.md +0 -0
  25. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/architecture/HYBRID_ANALYSIS_ARCHITECTURE.md +0 -0
  26. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/architecture/PHASE2_IR_STITCHING.md +0 -0
  27. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/architecture/PIPELINE_PRIMITIVES_USECASES.md +0 -0
  28. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/architecture/SALESFORCE_REPORT_IR.md +0 -0
  29. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/architecture/SEMANTIC_JOIN_RESOLUTION.md +0 -0
  30. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/architecture/SEMANTIC_SCHEMA_DESIGN.md +0 -0
  31. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/design/AGENT_DESIGN_NOTES.md +0 -0
  32. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/design/COLUMN_PROFILING.md +0 -0
  33. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/design/COLUMN_PROFILING_IMPLEMENTATION.md +0 -0
  34. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/design/EXTRACTION_DETECTION.md +0 -0
  35. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/design/PERFORMANCE_AND_QUALITY_SPECIALISTS.md +0 -0
  36. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/design/STREAMING_SUBAGENT_ARCHITECTURE.md +0 -0
  37. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/examples/memory_usage_examples.py +0 -0
  38. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/examples/pydantic_tool_customization_example.py +0 -0
  39. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/reference/AGENT_USER_GUIDE.md +0 -0
  40. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/reference/GETTING_STARTED.md +0 -0
  41. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/reference/MIGRATION_THREE_SQL.md +0 -0
  42. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/reference/SCOPE_LEVEL_LINEAGE_GUIDE.md +0 -0
  43. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/reference/SEMANTIC_DIFF_HARNESS.md +0 -0
  44. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/reference/SEMANTIC_DIMENSIONS_GUIDE.md +0 -0
  45. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/docs/reference/TYPE_ENUMS.md +0 -0
  46. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/pytest.ini +0 -0
  47. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/create_salesforce_reports.py +0 -0
  48. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/data_generation/utils.py +0 -0
  49. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/databricks-smoke.py +0 -0
  50. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/delete_salesforce_reports.py +0 -0
  51. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/populate_salesforce_schema.py +0 -0
  52. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/reset_demo_git_workspace.py +0 -0
  53. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/reset_demo_linear.py +0 -0
  54. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/snowflake_server.py +0 -0
  55. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/surreal-engine-bench.sh +0 -0
  56. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/surreal-fts-b2-corpus.sh +0 -0
  57. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/surreal-fts-bench.sh +0 -0
  58. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/scripts/surreal-fts-quality.sh +0 -0
  59. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/snowflake-mcp-config.yaml +0 -0
  60. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/__init__.py +0 -0
  61. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/app.py +0 -0
  62. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/auth_context.py +0 -0
  63. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/concept_cards.py +0 -0
  64. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/controlplane_identity.py +0 -0
  65. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_agents.py +0 -0
  66. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_context.py +0 -0
  67. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_logs.py +0 -0
  68. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_quickstart.py +0 -0
  69. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_runtime.py +0 -0
  70. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_semdiff_provision.py +0 -0
  71. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_setup.py +0 -0
  72. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_wizard_sync.py +0 -0
  73. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_workspaces.py +0 -0
  74. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/desktop_worktree.py +0 -0
  75. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/graph_availability.py +0 -0
  76. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/posthog_analytics.py +0 -0
  77. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/semantic_runtime.py +0 -0
  78. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/api/serve.py +0 -0
  79. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/context_projects/__init__.py +0 -0
  80. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/context_projects/airflow_discovery.py +0 -0
  81. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/context_projects/dbt_plugin.py +0 -0
  82. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/__init__.py +0 -0
  83. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/backward_dryrun.py +0 -0
  84. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/clustering_metrics.py +0 -0
  85. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/drop_snowflake_tables.py +0 -0
  86. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/ephemeral_lineage_report.py +0 -0
  87. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/eval_clustering.py +0 -0
  88. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/list_ephemeral_models.py +0 -0
  89. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/refingerprint_cache.py +0 -0
  90. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/regen_semantic_goldens.py +0 -0
  91. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/reset_git_workspace.py +0 -0
  92. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/reset_linear_workspace.py +0 -0
  93. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/reset_project.py +0 -0
  94. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/run_dbt_workflow.py +0 -0
  95. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/seed_census.py +0 -0
  96. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/semantic_goldens.py +0 -0
  97. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/__init__.py +0 -0
  98. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/fts_bench.py +0 -0
  99. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/fts_cells.py +0 -0
  100. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/fts_corpus.py +0 -0
  101. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/fts_corpus_dump.py +0 -0
  102. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/fts_coverage.py +0 -0
  103. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/fts_coverage_report.py +0 -0
  104. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/fts_oracle.py +0 -0
  105. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/fts_quality.py +0 -0
  106. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/fts_quality_bench.py +0 -0
  107. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/log_parse.py +0 -0
  108. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/membership.py +0 -0
  109. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/membership_qualification.py +0 -0
  110. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/membership_runner.py +0 -0
  111. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/membership_storage.py +0 -0
  112. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/membership_storage_support.py +0 -0
  113. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/report.py +0 -0
  114. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/surreal_bench/runner.py +0 -0
  115. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/__init__.py +0 -0
  116. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/README.md +0 -0
  117. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/__init__.py +0 -0
  118. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/cli.py +0 -0
  119. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/db_names.py +0 -0
  120. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/dbt_compile.py +0 -0
  121. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/diff_runner.py +0 -0
  122. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/expected_changes.py +0 -0
  123. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/column_rename_downstream/fixture.yaml +0 -0
  124. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/column_rename_downstream/mutation.diff +0 -0
  125. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_coarsen/fixture.yaml +0 -0
  126. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_coarsen/mutation.diff +0 -0
  127. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_deleted_leaf_model/fixture.yaml +0 -0
  128. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_deleted_leaf_model/mutation.diff +0 -0
  129. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_fanout_compound_oli/fixture.yaml +0 -0
  130. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_fanout_compound_oli/mutation.diff +0 -0
  131. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_gold_control/fixture.yaml +0 -0
  132. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_gold_control/mutation.diff +0 -0
  133. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_v1_003_user_telemetry/fixture.yaml +0 -0
  134. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_v1_003_user_telemetry/mutation.diff +0 -0
  135. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures_loader.py +0 -0
  136. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/ingest.py +0 -0
  137. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/lifecycle.py +0 -0
  138. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/semantic_diff/source_prep.py +0 -0
  139. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/surreal/__init__.py +0 -0
  140. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/surreal/desktop_mcp.py +0 -0
  141. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/devtools/unified_graph/unified_cli.py +0 -0
  142. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/mcp/__init__.py +0 -0
  143. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/mcp/runner.py +0 -0
  144. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/mcp/server.py +0 -0
  145. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/observability/__init__.py +0 -0
  146. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/observability/desktop_logfire.py +0 -0
  147. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/observability/local_otlp_export.py +0 -0
  148. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/observability/local_span_export.py +0 -0
  149. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/templates/__init__.py +0 -0
  150. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/templates/typedef_config.yaml.j2 +0 -0
  151. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/typedef_cli.py +0 -0
  152. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/utils/__init__.py +0 -0
  153. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/utils/databricks.py +0 -0
  154. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/utils/databricks_oauth.py +0 -0
  155. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/utils/dbt.py +0 -0
  156. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/utils/dbt_profile.py +0 -0
  157. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/utils/env.py +0 -0
  158. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/utils/git.py +0 -0
  159. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/utils/gitignore.py +0 -0
  160. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/utils/logging.py +0 -0
  161. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/src/lineage/utils/snowflake.py +0 -0
  162. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/__init__.py +0 -0
  163. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_app_lifespan.py +0 -0
  164. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_app_logfire.py +0 -0
  165. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_app_retention_wiring.py +0 -0
  166. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_concept_cards.py +0 -0
  167. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_databricks_auth_wiring.py +0 -0
  168. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_agents_clone_backend.py +0 -0
  169. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_agents_runtime.py +0 -0
  170. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_agents_ticket_resolution.py +0 -0
  171. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_airflow_snapshot.py +0 -0
  172. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_clerk_auth.py +0 -0
  173. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_context_reader_cache.py +0 -0
  174. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_databases_delete.py +0 -0
  175. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_databases_edit.py +0 -0
  176. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_databricks_oauth.py +0 -0
  177. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_databricks_setup.py +0 -0
  178. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_delete_endpoints.py +0 -0
  179. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_diagnostics.py +0 -0
  180. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_local_clone.py +0 -0
  181. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_logs.py +0 -0
  182. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_orphan_flags.py +0 -0
  183. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_posthog.py +0 -0
  184. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_quickstart.py +0 -0
  185. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_repo_projects_discovery.py +0 -0
  186. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_runtime.py +0 -0
  187. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_salesforce.py +0 -0
  188. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_save_env_credentials.py +0 -0
  189. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_search.py +0 -0
  190. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_secondary_roles_hook.py +0 -0
  191. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_semdiff_provision.py +0 -0
  192. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_setup_clone.py +0 -0
  193. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_setup_env_vars.py +0 -0
  194. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_sync_render_profile.py +0 -0
  195. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_telemetry.py +0 -0
  196. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces.py +0 -0
  197. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_adopt.py +0 -0
  198. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_context_kinds.py +0 -0
  199. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_delete.py +0 -0
  200. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_gold_triggers.py +0 -0
  201. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_integrations.py +0 -0
  202. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_preview_name.py +0 -0
  203. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_projects_and_repos.py +0 -0
  204. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_r3_r10.py +0 -0
  205. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_summary.py +0 -0
  206. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_target_scope.py +0 -0
  207. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_workspaces_wizard.py +0 -0
  208. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_worktree.py +0 -0
  209. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_worktree_clone.py +0 -0
  210. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_worktree_clone_token_scope.py +0 -0
  211. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_worktree_gold_queue.py +0 -0
  212. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_worktree_kind_target.py +0 -0
  213. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_desktop_worktree_resolution_scope.py +0 -0
  214. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_graph_availability_any_sentinel.py +0 -0
  215. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_local_otlp_export.py +0 -0
  216. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_no_legacy_surface.py +0 -0
  217. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_surreal_graph_availability.py +0 -0
  218. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_target_envelope_reads.py +0 -0
  219. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_validate_project_collisions.py +0 -0
  220. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_wizard_create_project_integration_persistence.py +0 -0
  221. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_workspace_clone_settings.py +0 -0
  222. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/api/test_worktree_registry_workspaces_shape.py +0 -0
  223. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/backends/__init__.py +0 -0
  224. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/backends/lineage/__init__.py +0 -0
  225. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/backends/lineage/test_search_enum_coverage.py +0 -0
  226. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/backends/lineage/test_surreal_search.py +0 -0
  227. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/conftest.py +0 -0
  228. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/__init__.py +0 -0
  229. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/surreal_bench/__init__.py +0 -0
  230. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/surreal_bench/test_fts_cells.py +0 -0
  231. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/surreal_bench/test_fts_coverage.py +0 -0
  232. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/surreal_bench/test_fts_quality.py +0 -0
  233. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/surreal_bench/test_log_parse.py +0 -0
  234. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/surreal_bench/test_membership.py +0 -0
  235. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/surreal_bench/test_membership_runner.py +0 -0
  236. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/surreal_bench/test_report.py +0 -0
  237. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/test_databricks_prepare_benchmark.py +0 -0
  238. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/test_justfile_recipes.py +0 -0
  239. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/test_repo_skill_docs.py +0 -0
  240. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/test_sf_login.py +0 -0
  241. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/test_tdh_doctor.py +0 -0
  242. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/test_typedef_home_provision.py +0 -0
  243. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/devtools/test_worktree_reclaim.py +0 -0
  244. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/docs/test_desktop_posthog_event_docs.py +0 -0
  245. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/integration/__init__.py +0 -0
  246. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/integration/test_semantic_diff_harness.py +0 -0
  247. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/mcp/__init__.py +0 -0
  248. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/mcp/test_desktop_graph_inventory_surface.py +0 -0
  249. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/mcp/test_desktop_mcp_retry.py +0 -0
  250. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/mcp/test_list_projects.py +0 -0
  251. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/mcp/test_server.py +0 -0
  252. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/observability/test_no_raw_stream_filehandler.py +0 -0
  253. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/test_git_utils.py +0 -0
  254. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/test_gitignore_utils.py +0 -0
  255. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/test_helpers_semantic.py +0 -0
  256. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/test_local_clone_util.py +0 -0
  257. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/test_model_tier_validation.py +0 -0
  258. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/test_template_yaml_escaping.py +0 -0
  259. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/test_typedef_cli_import_budget.py +0 -0
  260. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/test_unified_cli_airflow.py +0 -0
  261. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/test_unified_cli_fast.py +0 -0
  262. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/test_unified_cli_semantic.py +0 -0
  263. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/context_projects/test_airflow_discovery.py +0 -0
  264. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/context_projects/test_dbt_plugin.py +0 -0
  265. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/devtools/__init__.py +0 -0
  266. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/devtools/test_semdiff_expected_changes.py +0 -0
  267. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/devtools/test_semdiff_harness_units.py +0 -0
  268. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/devtools/test_semdiff_lifecycle.py +0 -0
  269. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/devtools/test_semdiff_lifecycle_io.py +0 -0
  270. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/devtools/test_semdiff_lifecycle_provisioning.py +0 -0
  271. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/formula/__init__.py +0 -0
  272. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/utils/__init__.py +0 -0
  273. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/utils/test_databricks_utils.py +0 -0
  274. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/utils/test_dbt_docs_generate.py +0 -0
  275. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/utils/test_dbt_profile.py +0 -0
  276. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/utils/test_logging.py +0 -0
  277. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/utils/test_run_dbt_command.py +0 -0
  278. {typedef_data_intelligence-0.40.0 → typedef_data_intelligence-0.41.0}/tests/unit/utils/test_snowflake_utils.py +0 -0
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.41.0](https://github.com/typedef-ai/typedef/compare/typedef-data-intelligence-v0.40.0...typedef-data-intelligence-v0.41.0) (2026-07-13)
4
+
5
+
6
+ ### Features
7
+
8
+ * **graph:** activate lightweight system membership (TD-3882) ([#1173](https://github.com/typedef-ai/typedef/issues/1173)) ([e91c42c](https://github.com/typedef-ai/typedef/commit/e91c42cc491b2fc8265536b8f467b61527e67071))
9
+
3
10
  ## [0.40.0](https://github.com/typedef-ai/typedef/compare/typedef-data-intelligence-v0.39.1...typedef-data-intelligence-v0.40.0) (2026-07-10)
4
11
 
5
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: typedef-data-intelligence
3
- Version: 0.40.0
3
+ Version: 0.41.0
4
4
  Summary: Unified lineage management and AI-powered analytics platform for dbt projects
5
5
  Project-URL: Homepage, https://typedef.ai
6
6
  Project-URL: Repository, https://github.com/typedef-ai/data-intelligence
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "typedef-data-intelligence"
3
- version = "0.40.0"
3
+ version = "0.41.0"
4
4
  description = "Unified lineage management and AI-powered analytics platform for dbt projects"
5
5
  readme = "README.pypi.md"
6
6
  license = "LicenseRef-Proprietary"
@@ -25,6 +25,7 @@ from typing import TYPE_CHECKING, Any
25
25
  from agent.api import shutdown_event
26
26
  from agent.controlplane_context import get_typedef_context
27
27
  from core.backends.controlplane import LLMProxyConfig
28
+ from core.models.desktop import ProjectHealthInfo, ProjectsHealthResponse
28
29
  from core.models.observability import Outcome
29
30
  from core.observability.manifest import record_op_end, record_op_start
30
31
  from fastapi import APIRouter, Depends, HTTPException, Request
@@ -2478,12 +2479,9 @@ def _maybe_migrate_workspace_graph(
2478
2479
  return True
2479
2480
  except RuntimeError:
2480
2481
  raise
2481
- except Exception: # noqa: BLE001
2482
- log.warning(
2483
- "TD-2959 graph migration probe failed; continuing with sync",
2484
- exc_info=True,
2485
- )
2486
- return False
2482
+ except Exception as exc: # noqa: BLE001
2483
+ log.error("graph migration probe failed; aborting sync", exc_info=True)
2484
+ raise RuntimeError(f"Graph migration probe failed: {exc}") from exc
2487
2485
 
2488
2486
 
2489
2487
  def _build_one_project(
@@ -3403,8 +3401,8 @@ def _project_has_graph_data(graph_db: str, project_name: str) -> bool:
3403
3401
  return False
3404
3402
 
3405
3403
 
3406
- @router.get("/projects/health")
3407
- async def projects_health():
3404
+ @router.get("/projects/health", response_model=ProjectsHealthResponse)
3405
+ async def projects_health() -> ProjectsHealthResponse:
3408
3406
  """Per-project sync health for all configured projects.
3409
3407
 
3410
3408
  Returns sync_status and sync_error per project so the frontend
@@ -3458,12 +3456,22 @@ async def projects_health():
3458
3456
  active_graph_db = gdb if (isinstance(gdb, str) and gdb) else active_ws_name
3459
3457
  elif active_ws_name:
3460
3458
  active_graph_db = active_ws_name
3461
- active_needs_migration = bool(
3462
- active_ws_name and workspace_needs_graph_migration(active_ws_name)
3463
- )
3459
+ active_migration_error: str | None = None
3460
+ try:
3461
+ active_needs_migration = bool(
3462
+ active_ws_name and workspace_needs_graph_migration(active_ws_name)
3463
+ )
3464
+ except Exception as exc: # noqa: BLE001
3465
+ logger.debug(
3466
+ "graph marker probe failed for %r; reporting migration required",
3467
+ active_ws_name,
3468
+ exc_info=True,
3469
+ )
3470
+ active_needs_migration = True
3471
+ active_migration_error = str(exc)
3464
3472
 
3465
3473
  projects = list_all_projects_raw(cfg)
3466
- result: list[dict] = []
3474
+ result: list[ProjectHealthInfo] = []
3467
3475
  # Pool one SurrealDB connection per graph_db across the per-project
3468
3476
  # ingest-version probes. This endpoint is polled every ~5s, so opening a
3469
3477
  # fresh connection per project was O(projects) churn (TD-3196 review).
@@ -3520,19 +3528,20 @@ async def projects_health():
3520
3528
  _active_running_sync_id(name, ws_name) if sync_status == "running" else None
3521
3529
  )
3522
3530
  result.append(
3523
- {
3524
- "name": name,
3525
- "graph_name": proj.get("graph_name"),
3526
- "sync_status": sync_status,
3527
- "sync_error": sync_error,
3528
- "last_synced_commit": proj.get("last_synced_commit"),
3529
- "needs_migration": needs_migration,
3530
- "ingest_version_mismatch": version_mismatch,
3531
- "workspace": ws_name,
3531
+ ProjectHealthInfo(
3532
+ name=name,
3533
+ graph_name=proj.get("graph_name"),
3534
+ sync_status=sync_status,
3535
+ sync_error=sync_error,
3536
+ last_synced_commit=proj.get("last_synced_commit"),
3537
+ needs_migration=needs_migration,
3538
+ migration_error=active_migration_error,
3539
+ ingest_version_mismatch=version_mismatch,
3540
+ workspace=ws_name,
3532
3541
  # sync_id of the in-flight sync (when running) so a client that
3533
3542
  # didn't start it can attach to the progress stream.
3534
- "active_sync_id": active_sync_id,
3535
- }
3543
+ active_sync_id=active_sync_id,
3544
+ )
3536
3545
  )
3537
3546
 
3538
3547
  for _c in _conn_cache.values():
@@ -3542,7 +3551,7 @@ async def projects_health():
3542
3551
  except Exception: # noqa: BLE001
3543
3552
  logger.debug("graph conn close failed", exc_info=True)
3544
3553
 
3545
- return {"projects": result}
3554
+ return ProjectsHealthResponse(projects=result)
3546
3555
 
3547
3556
 
3548
3557
  # ── Endpoints ─────────────────────────────────────────────────────────
@@ -13,6 +13,7 @@ import yaml
13
13
  from fastapi import FastAPI
14
14
  from fastapi.testclient import TestClient
15
15
  from lineage.api import desktop_setup
16
+ from lineage.api.desktop_workspaces import router as workspaces_router
16
17
  from lineage.utils.dbt import DbtDocsResult
17
18
 
18
19
 
@@ -29,6 +30,38 @@ def _build_client(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> TestClient
29
30
  return TestClient(app)
30
31
 
31
32
 
33
+ def test_workspace_crud_creation_stamps_current_marker_without_graph_drop(
34
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
35
+ ) -> None:
36
+ from core.migrations import graph_migration
37
+
38
+ client = _build_client(tmp_path, monkeypatch)
39
+ core_paths.config_path().write_text(
40
+ yaml.safe_dump(
41
+ {
42
+ "lineage": {
43
+ "backend": "surrealdb",
44
+ "url": "ws://127.0.0.1:3567",
45
+ },
46
+ "repos": {},
47
+ "workspaces": {},
48
+ }
49
+ ),
50
+ encoding="utf-8",
51
+ )
52
+ client.app.include_router(workspaces_router)
53
+ monkeypatch.setattr(
54
+ graph_migration,
55
+ "drop_legacy_graph",
56
+ lambda *_args, **_kwargs: pytest.fail("fresh creation must not drop a graph"),
57
+ )
58
+
59
+ response = client.post("/desktop/workspaces", json={"name": "ws2"})
60
+
61
+ assert response.status_code == 200
62
+ assert graph_migration.workspace_needs_graph_migration("ws2") is False
63
+
64
+
32
65
  def _reset_manifest(monkeypatch: pytest.MonkeyPatch) -> str:
33
66
  monkeypatch.setattr(session_mod, "_session_id", None)
34
67
  monkeypatch.delenv(session_mod.SESSION_ID_ENV, raising=False)
@@ -99,6 +132,42 @@ def _seed_repo(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> tuple[TestCli
99
132
  return client, "repo1"
100
133
 
101
134
 
135
+ def test_setup_creation_stamps_current_marker_without_graph_drop(
136
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
137
+ ) -> None:
138
+ from core.migrations import graph_migration
139
+
140
+ client, repo_key = _seed_repo(tmp_path, monkeypatch)
141
+ expected_clone = core_paths.projects_dir() / "analytics"
142
+ expected_clone.mkdir(parents=True)
143
+ (expected_clone / "dbt_project.yml").write_text(
144
+ "name: analytics\nprofile: analytics_profile\n",
145
+ encoding="utf-8",
146
+ )
147
+ monkeypatch.setattr(
148
+ graph_migration,
149
+ "drop_legacy_graph",
150
+ lambda *_args, **_kwargs: pytest.fail("fresh setup must not drop a graph"),
151
+ )
152
+ monkeypatch.setattr(
153
+ "lineage.api.desktop_worktree._queue_gold_provisioning",
154
+ lambda *_args, **_kwargs: None,
155
+ )
156
+
157
+ response = client.post(
158
+ "/desktop/setup/create-project",
159
+ json={
160
+ "name": repo_key,
161
+ "git_url": "https://github.com/acme/analytics.git",
162
+ "backend": "duckdb",
163
+ "duckdb_path": str(tmp_path / "warehouse.duckdb"),
164
+ },
165
+ )
166
+
167
+ assert response.status_code == 200, response.text
168
+ assert graph_migration.workspace_needs_graph_migration(repo_key) is False
169
+
170
+
102
171
  def _collect_sse(response) -> list[tuple[str, dict]]:
103
172
  events: list[tuple[str, dict]] = []
104
173
  event_type: str | None = None
@@ -1,15 +1,33 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import json
3
4
  import logging
5
+ import sys
6
+ from collections.abc import Iterable
4
7
  from pathlib import Path
5
8
  from types import SimpleNamespace
9
+ from typing import Callable
10
+ from unittest.mock import AsyncMock, Mock
6
11
 
7
12
  import core.observability.manifest as manifest_mod
8
13
  import core.observability.session as session_mod
9
14
  import pytest
15
+ from fastapi import FastAPI
16
+ from fastapi.testclient import TestClient
10
17
  from lineage.api import desktop_sync
11
18
 
12
19
 
20
+ def _collect_sse_data(lines: Iterable[str | bytes]) -> list[dict[str, object]]:
21
+ events: list[dict[str, object]] = []
22
+ for line in lines:
23
+ text = line.decode("utf-8") if isinstance(line, bytes) else line
24
+ if text.startswith("data: "):
25
+ payload = json.loads(text.removeprefix("data: "))
26
+ assert isinstance(payload, dict)
27
+ events.append(payload)
28
+ return events
29
+
30
+
13
31
  class EscalatingProcess:
14
32
  def __init__(self):
15
33
  self.pid = 4242
@@ -337,6 +355,270 @@ class _NotSetEvent:
337
355
  return False
338
356
 
339
357
 
358
+ def _stub_sync_worker_shell(
359
+ monkeypatch: pytest.MonkeyPatch, tmp_path: Path
360
+ ) -> None:
361
+ shared_pool = SimpleNamespace(
362
+ install_pool_signal_handlers=lambda: None,
363
+ shutdown_shared_executor=lambda: None,
364
+ )
365
+ monkeypatch.setitem(
366
+ sys.modules,
367
+ "ingest.static_loaders.shared_pool",
368
+ shared_pool,
369
+ )
370
+ monkeypatch.setattr(
371
+ desktop_sync, "_filter_syncable_specs", lambda _ws, specs, _log: specs
372
+ )
373
+ monkeypatch.setattr(
374
+ desktop_sync, "_workspace_syncable_project_names", lambda *_: set()
375
+ )
376
+ monkeypatch.setattr(desktop_sync, "_child_resource_diagnostics", lambda: "test")
377
+ monkeypatch.setattr(desktop_sync, "_capture_sync_failed_analytics", lambda *_: None)
378
+ monkeypatch.setattr("core.paths.logs_dir", lambda: tmp_path)
379
+
380
+
381
+ @pytest.mark.parametrize(
382
+ "migration_error",
383
+ (
384
+ "Graph migration probe failed: marker unreadable",
385
+ "Graph migration failed: reset denied",
386
+ ),
387
+ )
388
+ def test_sync_worker_migration_failure_emits_one_terminal_error_and_skips_builds(
389
+ monkeypatch: pytest.MonkeyPatch,
390
+ tmp_path: Path,
391
+ migration_error: str,
392
+ ) -> None:
393
+ _stub_sync_worker_shell(monkeypatch, tmp_path)
394
+
395
+ def _raise_reset_failure(
396
+ _workspace: str,
397
+ _projects: list[desktop_sync.ProjectBuildSpec],
398
+ _queue: _RecordingQueue,
399
+ _log: logging.Logger,
400
+ ) -> bool:
401
+ raise RuntimeError(migration_error)
402
+
403
+ build_one_project = Mock()
404
+ monkeypatch.setattr(
405
+ desktop_sync,
406
+ "_maybe_migrate_workspace_graph",
407
+ _raise_reset_failure,
408
+ )
409
+ monkeypatch.setattr(desktop_sync, "_build_one_project", build_one_project)
410
+ queue = _RecordingQueue()
411
+
412
+ desktop_sync._sync_worker(
413
+ "ws",
414
+ "sync-reset-failure",
415
+ [desktop_sync.ProjectBuildSpec(name="analytics")],
416
+ queue,
417
+ _NotSetEvent(),
418
+ )
419
+
420
+ terminal_errors = [
421
+ event
422
+ for event in queue.events
423
+ if event["stage"] == "error" and event["status"] == "error"
424
+ ]
425
+ assert len(terminal_errors) == 1
426
+ build_one_project.assert_not_called()
427
+
428
+
429
+ def test_sync_probe_failure_serializes_one_terminal_sse_error_without_builds(
430
+ monkeypatch: pytest.MonkeyPatch,
431
+ tmp_path: Path,
432
+ ) -> None:
433
+ _stub_sync_worker_shell(monkeypatch, tmp_path)
434
+ _stub_drain_finalization(monkeypatch)
435
+ desktop_sync._sync_ops.clear()
436
+ desktop_sync.shutdown_event.clear()
437
+ build_one_project = Mock()
438
+
439
+ def _raise_probe_failure(
440
+ _workspace: str,
441
+ _projects: list[desktop_sync.ProjectBuildSpec],
442
+ _queue: _RecordingQueue,
443
+ _log: logging.Logger,
444
+ ) -> bool:
445
+ raise RuntimeError("Graph migration probe failed: marker unreadable")
446
+
447
+ process = Mock(pid=4242, exitcode=0)
448
+ process.is_alive.return_value = False
449
+ process_factory = Mock(return_value=process)
450
+
451
+ def _run_worker() -> None:
452
+ call = process_factory.call_args
453
+ call.kwargs["target"](*call.kwargs["args"])
454
+
455
+ process.start.side_effect = _run_worker
456
+ monkeypatch.setattr(desktop_sync, "Process", process_factory)
457
+ monkeypatch.setattr(
458
+ desktop_sync, "_maybe_migrate_workspace_graph", _raise_probe_failure
459
+ )
460
+ monkeypatch.setattr(desktop_sync, "_build_one_project", build_one_project)
461
+ monkeypatch.setattr(
462
+ desktop_sync, "capture_backend_event_from_request", AsyncMock()
463
+ )
464
+ app = FastAPI()
465
+ app.include_router(desktop_sync.router)
466
+
467
+ with TestClient(app) as client:
468
+ started = client.post(
469
+ "/desktop/sync/",
470
+ json={
471
+ "workspace_name": "ws",
472
+ "project_name": "analytics",
473
+ },
474
+ )
475
+ assert started.status_code == 200
476
+ sync_id = started.json()["sync_id"]
477
+ with client.stream("GET", f"/desktop/sync/{sync_id}/progress") as response:
478
+ serialized = _collect_sse_data(response.iter_lines())
479
+
480
+ terminal_errors = [
481
+ event
482
+ for event in serialized
483
+ if event["stage"] == "error" and event["status"] == "error"
484
+ ]
485
+ assert len(terminal_errors) == 1
486
+ build_one_project.assert_not_called()
487
+
488
+
489
+ def test_collect_sse_data_decodes_byte_lines() -> None:
490
+ assert _collect_sse_data([b'data: {"status": "completed"}']) == [
491
+ {"status": "completed"}
492
+ ]
493
+
494
+
495
+ def test_migration_forces_every_context_full_then_second_worker_run_is_incremental(
496
+ monkeypatch: pytest.MonkeyPatch,
497
+ tmp_path: Path,
498
+ ) -> None:
499
+ _stub_sync_worker_shell(monkeypatch, tmp_path)
500
+ migration_results = iter((True, False))
501
+ monkeypatch.setattr(
502
+ desktop_sync,
503
+ "_maybe_migrate_workspace_graph",
504
+ lambda *_: next(migration_results),
505
+ )
506
+ build_one_project = Mock(
507
+ return_value=desktop_sync._ProjectOutcome(status="completed")
508
+ )
509
+ monkeypatch.setattr(desktop_sync, "_build_one_project", build_one_project)
510
+ monkeypatch.setattr(desktop_sync, "_workspace_l1_missing", lambda _db: False)
511
+ monkeypatch.setattr(
512
+ desktop_sync, "_run_concepts_finalize", lambda *_args, **_kwargs: None
513
+ )
514
+ specs = [
515
+ desktop_sync.ProjectBuildSpec(name="orders"),
516
+ desktop_sync.ProjectBuildSpec(name="customers"),
517
+ ]
518
+
519
+ for sync_id in ("sync-migrate", "sync-noop"):
520
+ desktop_sync._sync_worker(
521
+ "ws",
522
+ sync_id,
523
+ specs,
524
+ _RecordingQueue(),
525
+ _NotSetEvent(),
526
+ )
527
+
528
+ assert [call.args[3] for call in build_one_project.call_args_list] == [
529
+ True,
530
+ True,
531
+ False,
532
+ False,
533
+ ]
534
+
535
+
536
+ def test_sync_route_migrates_once_and_forces_every_context_full(
537
+ monkeypatch: pytest.MonkeyPatch,
538
+ tmp_path: Path,
539
+ ) -> None:
540
+ import core.paths as core_paths
541
+ from core.migrations import graph_migration
542
+
543
+ _stub_sync_worker_shell(monkeypatch, tmp_path)
544
+ _stub_drain_finalization(monkeypatch)
545
+ monkeypatch.setenv("TYPEDEF_HOME", str(tmp_path))
546
+ monkeypatch.setenv("TYPEDEF_DEV_MODE", "1")
547
+ core_paths.typedef_home.cache_clear()
548
+ desktop_sync._sync_ops.clear()
549
+ desktop_sync.shutdown_event.clear()
550
+ marker = graph_migration.graph_marker_path(tmp_path, "ws")
551
+ marker.parent.mkdir(parents=True)
552
+ marker.write_text('{"workspace": "ws"}', encoding="utf-8")
553
+ drop_calls: list[str] = []
554
+
555
+ def _drop_and_stamp(
556
+ workspace: str, *, progress_cb: Callable[[str, int, int], None]
557
+ ) -> SimpleNamespace:
558
+ drop_calls.append(workspace)
559
+ progress_cb("drop", 1, 1)
560
+ graph_migration.mark_workspace_graph_compatible(
561
+ workspace, home=tmp_path, reason="test_migration"
562
+ )
563
+ return SimpleNamespace(applied=True, cleared_context_entries=2, errors=[])
564
+
565
+ monkeypatch.setattr(graph_migration, "drop_legacy_graph", _drop_and_stamp)
566
+ build_one_project = Mock(
567
+ return_value=desktop_sync._ProjectOutcome(status="completed")
568
+ )
569
+ monkeypatch.setattr(desktop_sync, "_build_one_project", build_one_project)
570
+ monkeypatch.setattr(desktop_sync, "_workspace_l1_missing", lambda _db: False)
571
+ monkeypatch.setattr(
572
+ desktop_sync, "_run_concepts_finalize", lambda *_args, **_kwargs: None
573
+ )
574
+ process_factory = Mock()
575
+ processes = [Mock(pid=4242, exitcode=0), Mock(pid=4243, exitcode=0)]
576
+ for process in processes:
577
+ process.is_alive.return_value = False
578
+
579
+ def _run_worker() -> None:
580
+ call = process_factory.call_args
581
+ call.kwargs["target"](*call.kwargs["args"])
582
+
583
+ process.start.side_effect = _run_worker
584
+ process_factory.side_effect = processes
585
+ monkeypatch.setattr(desktop_sync, "Process", process_factory)
586
+ monkeypatch.setattr(
587
+ desktop_sync, "capture_backend_event_from_request", AsyncMock()
588
+ )
589
+ app = FastAPI()
590
+ app.include_router(desktop_sync.router)
591
+ request_body = {
592
+ "workspace_name": "ws",
593
+ "project_name": "orders",
594
+ "projects": [
595
+ {"name": "orders", "full": False},
596
+ {"name": "customers", "full": False},
597
+ ],
598
+ }
599
+
600
+ with TestClient(app) as client:
601
+ for _expected_drop_count in (1, 1):
602
+ started = client.post("/desktop/sync/", json=request_body)
603
+ assert started.status_code == 200
604
+ sync_id = started.json()["sync_id"]
605
+ with client.stream(
606
+ "GET", f"/desktop/sync/{sync_id}/progress"
607
+ ) as response:
608
+ assert any(
609
+ event["status"] == "completed"
610
+ for event in _collect_sse_data(response.iter_lines())
611
+ )
612
+
613
+ assert drop_calls == ["ws"]
614
+ assert [call.args[3] for call in build_one_project.call_args_list] == [
615
+ True,
616
+ True,
617
+ False,
618
+ False,
619
+ ]
620
+
621
+
340
622
  def test_graph_migration_progress_events_are_nonterminal(monkeypatch):
341
623
  from core.migrations import graph_migration
342
624
 
@@ -365,6 +647,28 @@ def test_graph_migration_progress_events_are_nonterminal(monkeypatch):
365
647
  assert any("flagged for resync" in event["message"] for event in migrate_events)
366
648
 
367
649
 
650
+ def test_graph_migration_probe_error_aborts_before_project_build(monkeypatch) -> None:
651
+ """An unreadable marker must stop sync before any project work begins."""
652
+ from core.migrations import graph_migration
653
+
654
+ def _raise_marker_io_error(_workspace: str) -> bool:
655
+ raise OSError("marker unreadable")
656
+
657
+ monkeypatch.setattr(
658
+ graph_migration,
659
+ "workspace_needs_graph_migration",
660
+ _raise_marker_io_error,
661
+ )
662
+
663
+ with pytest.raises(RuntimeError, match="Graph migration probe failed"):
664
+ desktop_sync._maybe_migrate_workspace_graph(
665
+ "ws",
666
+ [],
667
+ _RecordingQueue(),
668
+ logging.getLogger("test"),
669
+ )
670
+
671
+
368
672
  def _write_project_config(
369
673
  cfg_path: Path,
370
674
  project_name: str,
@@ -1410,18 +1714,75 @@ def test_projects_health_stamps_active_workspace_on_name_collision(
1410
1714
  )
1411
1715
 
1412
1716
  res = asyncio.run(desktop_sync.projects_health())
1413
- rows = res["projects"]
1717
+ rows = res.projects
1414
1718
 
1415
1719
  # Only the ACTIVE workspace's projects are enumerated.
1416
- assert {r["name"] for r in rows} == {"shared", "alpha"}
1720
+ assert {r.name for r in rows} == {"shared", "alpha"}
1417
1721
  # Every row — including the colliding ``shared`` — is stamped with the
1418
1722
  # active workspace, NOT ws_b (the old last-writer-wins bug).
1419
1723
  for r in rows:
1420
- assert r["workspace"] == "ws_a", (
1421
- f"{r['name']!r} mis-stamped {r['workspace']!r} (expected ws_a)"
1724
+ assert r.workspace == "ws_a", (
1725
+ f"{r.name!r} mis-stamped {r.workspace!r} (expected ws_a)"
1422
1726
  )
1423
1727
 
1424
1728
 
1729
+ def test_projects_health_reports_marker_io_error_without_crashing(
1730
+ monkeypatch, tmp_path, caplog
1731
+ ) -> None:
1732
+ """Health remains available when sync's marker probe must fail closed."""
1733
+ import asyncio
1734
+
1735
+ import yaml
1736
+ from core import paths as core_paths
1737
+ from core.migrations import graph_migration
1738
+
1739
+ cfg_file = tmp_path / "config.yaml"
1740
+ cfg_file.write_text(
1741
+ yaml.safe_dump(
1742
+ {
1743
+ "active_workspace": "ws",
1744
+ "repos": {},
1745
+ "workspaces": {
1746
+ "ws": {
1747
+ "graph_db": "ws",
1748
+ "context": [{"project": {"name": "project"}}],
1749
+ }
1750
+ },
1751
+ }
1752
+ ),
1753
+ encoding="utf-8",
1754
+ )
1755
+ monkeypatch.setattr(core_paths, "config_path", lambda: cfg_file)
1756
+
1757
+ def _raise_marker_io_error(_workspace: str) -> bool:
1758
+ raise OSError("marker unreadable")
1759
+
1760
+ monkeypatch.setattr(
1761
+ graph_migration,
1762
+ "workspace_needs_graph_migration",
1763
+ _raise_marker_io_error,
1764
+ )
1765
+ monkeypatch.setattr(desktop_sync, "_open_surreal_for_graph", lambda _gdb: None)
1766
+ monkeypatch.setattr(
1767
+ desktop_sync,
1768
+ "_project_has_graph_data",
1769
+ lambda _gdb, _name: False,
1770
+ )
1771
+
1772
+ with caplog.at_level(logging.DEBUG, logger=desktop_sync.logger.name):
1773
+ response = asyncio.run(desktop_sync.projects_health())
1774
+
1775
+ assert len(response.projects) == 1
1776
+ project = response.projects[0]
1777
+ assert project.name == "project"
1778
+ assert project.needs_migration is True
1779
+ assert project.migration_error == "marker unreadable"
1780
+ marker_logs = [
1781
+ record for record in caplog.records if "graph marker probe failed" in record.message
1782
+ ]
1783
+ assert [record.levelno for record in marker_logs] == [logging.DEBUG]
1784
+
1785
+
1425
1786
  # ── TD-2950: silent-sync-death diagnostics ────────────────────────────
1426
1787
 
1427
1788