typedef-data-intelligence 0.34.0__tar.gz → 0.35.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.
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/CHANGELOG.md +15 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/PKG-INFO +1 -1
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/pyproject.toml +1 -1
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/app.py +20 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_quickstart.py +73 -11
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_setup.py +73 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_sync.py +130 -10
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_workspaces.py +125 -69
- typedef_data_intelligence-0.35.0/src/lineage/context_projects/__init__.py +27 -0
- typedef_data_intelligence-0.35.0/src/lineage/context_projects/airflow_discovery.py +304 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/context_projects/dbt_plugin.py +6 -1
- typedef_data_intelligence-0.35.0/tests/api/test_app_lifespan.py +48 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_quickstart.py +191 -0
- typedef_data_intelligence-0.35.0/tests/api/test_desktop_repo_projects_discovery.py +272 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_setup.py +59 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_setup_clone.py +121 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_sync.py +394 -7
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/devtools/test_typedef_home_provision.py +354 -9
- typedef_data_intelligence-0.35.0/tests/unit/context_projects/test_airflow_discovery.py +266 -0
- typedef_data_intelligence-0.34.0/src/lineage/context_projects/__init__.py +0 -18
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/.dockerignore +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/.env.example +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/.gitignore +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/.justfile_help.txt +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/Dockerfile +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/Dockerfile.dev +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/Justfile +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/README.pypi.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/config.api.yml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/config.cli.yml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/config.desktop.yml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/config.ingest.unified.yml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/config.ingest.yml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docker-entrypoint.dev.sh +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/LINEAR_TICKETING_BACKEND.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/architecture/BUSINESS_CONCEPT_INDEX.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/architecture/CLUSTERING_ALGORITHM_DECISION.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/architecture/GENERIC_REPORT_SCHEMA.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/architecture/HYBRID_ANALYSIS_ARCHITECTURE.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/architecture/PHASE2_IR_STITCHING.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/architecture/PIPELINE_PRIMITIVES_USECASES.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/architecture/SALESFORCE_REPORT_IR.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/architecture/SEMANTIC_JOIN_RESOLUTION.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/architecture/SEMANTIC_SCHEMA_DESIGN.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/design/AGENT_DESIGN_NOTES.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/design/COLUMN_PROFILING.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/design/COLUMN_PROFILING_IMPLEMENTATION.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/design/EXTRACTION_DETECTION.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/design/PERFORMANCE_AND_QUALITY_SPECIALISTS.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/design/STREAMING_SUBAGENT_ARCHITECTURE.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/examples/memory_usage_examples.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/examples/pydantic_tool_customization_example.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/reference/AGENT_USER_GUIDE.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/reference/GETTING_STARTED.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/reference/MIGRATION_THREE_SQL.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/reference/SCOPE_LEVEL_LINEAGE_GUIDE.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/reference/SEMANTIC_DIFF_HARNESS.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/reference/SEMANTIC_DIMENSIONS_GUIDE.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/docs/reference/TYPE_ENUMS.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/pytest.ini +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/create_salesforce_reports.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/data_generation/utils.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/databricks-smoke.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/delete_salesforce_reports.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/populate_salesforce_schema.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/reset_demo_git_workspace.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/reset_demo_linear.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/snowflake_server.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/surreal-engine-bench.sh +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/surreal-fts-b2-corpus.sh +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/surreal-fts-bench.sh +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/scripts/surreal-fts-quality.sh +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/snowflake-mcp-config.yaml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/auth_context.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/concept_cards.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/controlplane_identity.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_agents.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_context.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_logs.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_runtime.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_semdiff_provision.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_wizard_sync.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/desktop_worktree.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/graph_availability.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/posthog_analytics.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/semantic_runtime.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/serve.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/backward_dryrun.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/clustering_metrics.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/drop_snowflake_tables.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/ephemeral_lineage_report.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/eval_clustering.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/list_ephemeral_models.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/refingerprint_cache.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/regen_semantic_goldens.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/reset_git_workspace.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/reset_linear_workspace.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/reset_project.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/run_dbt_workflow.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/seed_census.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/semantic_goldens.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/fts_bench.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/fts_cells.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/fts_corpus.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/fts_corpus_dump.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/fts_coverage.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/fts_coverage_report.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/fts_oracle.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/fts_quality.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/fts_quality_bench.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/log_parse.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/report.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/surreal_bench/runner.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/README.md +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/cli.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/db_names.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/dbt_compile.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/diff_runner.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/expected_changes.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/column_rename_downstream/fixture.yaml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/column_rename_downstream/mutation.diff +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_coarsen/fixture.yaml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_coarsen/mutation.diff +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_deleted_leaf_model/fixture.yaml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_deleted_leaf_model/mutation.diff +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_fanout_compound_oli/fixture.yaml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_fanout_compound_oli/mutation.diff +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_gold_control/fixture.yaml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_gold_control/mutation.diff +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_v1_003_user_telemetry/fixture.yaml +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures/grain_v1_003_user_telemetry/mutation.diff +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/fixtures_loader.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/ingest.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/lifecycle.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/semantic_diff/source_prep.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/surreal/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/surreal/desktop_mcp.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/devtools/unified_graph/unified_cli.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/mcp/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/mcp/runner.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/mcp/server.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/templates/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/templates/typedef_config.yaml.j2 +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/typedef_cli.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/utils/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/utils/databricks.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/utils/databricks_oauth.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/utils/dbt.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/utils/dbt_profile.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/utils/env.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/utils/git.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/utils/gitignore.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/utils/logging.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/utils/snowflake.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_concept_cards.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_databricks_auth_wiring.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_agents_clone_backend.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_agents_runtime.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_agents_ticket_resolution.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_airflow_snapshot.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_clerk_auth.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_context_reader_cache.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_databases_delete.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_databases_edit.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_databricks_oauth.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_databricks_setup.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_delete_endpoints.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_diagnostics.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_logs.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_orphan_flags.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_posthog.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_runtime.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_salesforce.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_save_env_credentials.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_search.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_secondary_roles_hook.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_semdiff_provision.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_setup_env_vars.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_sync_render_profile.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_telemetry.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_adopt.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_context_kinds.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_delete.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_gold_triggers.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_integrations.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_preview_name.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_projects_and_repos.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_r3_r10.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_summary.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_target_scope.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_workspaces_wizard.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_worktree.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_worktree_clone.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_worktree_clone_token_scope.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_worktree_gold_queue.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_worktree_kind_target.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_desktop_worktree_resolution_scope.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_graph_availability_any_sentinel.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_no_legacy_surface.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_surreal_graph_availability.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_target_envelope_reads.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_validate_project_collisions.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_wizard_create_project_integration_persistence.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_workspace_clone_settings.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/api/test_worktree_registry_workspaces_shape.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/backends/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/backends/lineage/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/backends/lineage/test_search_enum_coverage.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/backends/lineage/test_surreal_search.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/conftest.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/devtools/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/devtools/surreal_bench/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/devtools/surreal_bench/test_fts_cells.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/devtools/surreal_bench/test_fts_coverage.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/devtools/surreal_bench/test_fts_quality.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/devtools/surreal_bench/test_log_parse.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/devtools/surreal_bench/test_report.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/devtools/test_worktree_reclaim.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/docs/test_desktop_posthog_event_docs.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/integration/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/integration/test_semantic_diff_harness.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/mcp/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/mcp/test_desktop_mcp_retry.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/mcp/test_list_projects.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/mcp/test_server.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/test_git_utils.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/test_gitignore_utils.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/test_helpers_semantic.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/test_model_tier_validation.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/test_template_yaml_escaping.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/test_typedef_cli_import_budget.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/test_unified_cli_airflow.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/test_unified_cli_fast.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/test_unified_cli_semantic.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/context_projects/test_dbt_plugin.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/devtools/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/devtools/test_semdiff_expected_changes.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/devtools/test_semdiff_harness_units.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/devtools/test_semdiff_lifecycle.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/devtools/test_semdiff_lifecycle_io.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/devtools/test_semdiff_lifecycle_provisioning.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/formula/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/utils/__init__.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/utils/test_databricks_utils.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/utils/test_dbt_docs_generate.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/utils/test_dbt_profile.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/utils/test_logging.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/utils/test_run_dbt_command.py +0 -0
- {typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/tests/unit/utils/test_snowflake_utils.py +0 -0
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.35.0](https://github.com/typedef-ai/typedef/compare/typedef-data-intelligence-v0.34.0...typedef-data-intelligence-v0.35.0) (2026-07-06)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **desktop:** Airflow context-project discovery + multi-kind picker (TD-2647) ([#1079](https://github.com/typedef-ai/typedef/issues/1079)) ([0436af1](https://github.com/typedef-ai/typedef/commit/0436af1f8720643405921759be411ef39c783172))
|
|
9
|
+
* **observability:** add session manifest core + call-site instrumentation (TD-3826) ([#1098](https://github.com/typedef-ai/typedef/issues/1098)) ([8c6406a](https://github.com/typedef-ai/typedef/commit/8c6406a5d31d4429e7dbe0de011361e8fa235239))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* **desktop:** honor dbt subprojects in test home provisioning ([#1093](https://github.com/typedef-ai/typedef/issues/1093)) ([0064597](https://github.com/typedef-ai/typedef/commit/0064597f2fa74452356061a8f7d69b2158106eb0))
|
|
15
|
+
* harden matrix sync completion validation ([#1096](https://github.com/typedef-ai/typedef/issues/1096)) ([afbc22e](https://github.com/typedef-ai/typedef/commit/afbc22eff571a69d56d6d764c6e79dc692d6cf96))
|
|
16
|
+
* **ingest:** bound RTIF snapshot reader run selection (TD-3823) ([#1095](https://github.com/typedef-ai/typedef/issues/1095)) ([fff7d65](https://github.com/typedef-ai/typedef/commit/fff7d6510f7d54b029dadb29dfa4ef6958239162))
|
|
17
|
+
|
|
3
18
|
## [0.34.0](https://github.com/typedef-ai/typedef/compare/typedef-data-intelligence-v0.33.0...typedef-data-intelligence-v0.34.0) (2026-07-01)
|
|
4
19
|
|
|
5
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: typedef-data-intelligence
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.35.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
|
{typedef_data_intelligence-0.34.0 → typedef_data_intelligence-0.35.0}/src/lineage/api/app.py
RENAMED
|
@@ -326,6 +326,19 @@ async def lifespan(app: FastAPI):
|
|
|
326
326
|
len(removed_frontend_logs),
|
|
327
327
|
)
|
|
328
328
|
|
|
329
|
+
try:
|
|
330
|
+
from core.observability.manifest import record_session_start
|
|
331
|
+
from core.observability.session import mint_session_id
|
|
332
|
+
|
|
333
|
+
mint_session_id()
|
|
334
|
+
record_session_start({})
|
|
335
|
+
except Exception as exc:
|
|
336
|
+
logger.warning(
|
|
337
|
+
"Observability session manifest startup failed: %s",
|
|
338
|
+
exc,
|
|
339
|
+
exc_info=True,
|
|
340
|
+
)
|
|
341
|
+
|
|
329
342
|
# TD-3200 Phase 3: convert any already-workspaces-shape config from the
|
|
330
343
|
# pre-envelope ContextEntry/flat-LineageTarget shape to the
|
|
331
344
|
# ContextProject/BuildTarget envelope. Operates only on
|
|
@@ -733,6 +746,13 @@ async def lifespan(app: FastAPI):
|
|
|
733
746
|
"Failed to terminate active gold workers", exc_info=True
|
|
734
747
|
)
|
|
735
748
|
|
|
749
|
+
try:
|
|
750
|
+
from core.observability.manifest import finalize_open_ops
|
|
751
|
+
|
|
752
|
+
finalize_open_ops(outcome="cancelled")
|
|
753
|
+
except Exception:
|
|
754
|
+
logger.debug("Failed to finalize observability manifest ops", exc_info=True)
|
|
755
|
+
|
|
736
756
|
try:
|
|
737
757
|
from lineage.api.posthog_analytics import shutdown_shared_posthog_client
|
|
738
758
|
|
|
@@ -27,6 +27,8 @@ from typing import Any, Literal
|
|
|
27
27
|
import yaml
|
|
28
28
|
from agent.api import shutdown_event
|
|
29
29
|
from core.backends.controlplane import LLMProxyConfig
|
|
30
|
+
from core.models.observability import Outcome
|
|
31
|
+
from core.observability.manifest import record_op_end, record_op_start
|
|
30
32
|
from core.paths import (
|
|
31
33
|
config_path,
|
|
32
34
|
ensure_home,
|
|
@@ -144,6 +146,48 @@ _quickstart_ops: dict[str, QuickstartOperation] = {}
|
|
|
144
146
|
_quickstart_lock = threading.Lock()
|
|
145
147
|
|
|
146
148
|
|
|
149
|
+
def _quickstart_manifest_attrs() -> dict[str, str]:
|
|
150
|
+
return {
|
|
151
|
+
"project_name": QUICKSTART_PROJECT_NAME,
|
|
152
|
+
"display_name": QUICKSTART_DISPLAY_NAME,
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _quickstart_manifest_outcome(status: str | None) -> Outcome:
|
|
157
|
+
if status == "error":
|
|
158
|
+
return "error"
|
|
159
|
+
if status == "cancelled":
|
|
160
|
+
return "cancelled"
|
|
161
|
+
return "ok"
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _record_quickstart_start(quickstart_id: str) -> None:
|
|
165
|
+
record_op_start(
|
|
166
|
+
"setup",
|
|
167
|
+
"quickstart",
|
|
168
|
+
quickstart_id,
|
|
169
|
+
attrs=_quickstart_manifest_attrs(),
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _record_quickstart_end(
|
|
174
|
+
quickstart_id: str,
|
|
175
|
+
outcome: Outcome,
|
|
176
|
+
*,
|
|
177
|
+
error: str | None = None,
|
|
178
|
+
) -> None:
|
|
179
|
+
record_op_end("quickstart", quickstart_id, outcome, error=error)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _record_quickstart_event_end(quickstart_id: str, event: dict[str, Any]) -> None:
|
|
183
|
+
status = event.get("status")
|
|
184
|
+
outcome = _quickstart_manifest_outcome(str(status) if status is not None else None)
|
|
185
|
+
error = None
|
|
186
|
+
if outcome == "error":
|
|
187
|
+
error = str(event.get("message") or "Quick Start failed")
|
|
188
|
+
_record_quickstart_end(quickstart_id, outcome, error=error)
|
|
189
|
+
|
|
190
|
+
|
|
147
191
|
def _get_quickstart_op(quickstart_id: str) -> QuickstartOperation | None:
|
|
148
192
|
with _quickstart_lock:
|
|
149
193
|
return _quickstart_ops.get(quickstart_id)
|
|
@@ -908,6 +952,7 @@ def _watch_quickstart_process(quickstart_id: str) -> None:
|
|
|
908
952
|
if terminal_event is not None:
|
|
909
953
|
current.status = str(terminal_event.get("status", "completed"))
|
|
910
954
|
current.last_event = terminal_event
|
|
955
|
+
_record_quickstart_event_end(quickstart_id, terminal_event)
|
|
911
956
|
else:
|
|
912
957
|
current.status = "completed"
|
|
913
958
|
current.last_event = {
|
|
@@ -919,6 +964,7 @@ def _watch_quickstart_process(quickstart_id: str) -> None:
|
|
|
919
964
|
),
|
|
920
965
|
"status": "completed",
|
|
921
966
|
}
|
|
967
|
+
_record_quickstart_end(quickstart_id, "ok")
|
|
922
968
|
elif exit_code == 128 + signal.SIGTERM:
|
|
923
969
|
# TD-3192: SIGTERM-handler exit (143) is a clean cancel /
|
|
924
970
|
# shutdown, not a crash — surface as cancelled.
|
|
@@ -929,6 +975,7 @@ def _watch_quickstart_process(quickstart_id: str) -> None:
|
|
|
929
975
|
),
|
|
930
976
|
"status": "cancelled",
|
|
931
977
|
}
|
|
978
|
+
_record_quickstart_end(quickstart_id, "cancelled")
|
|
932
979
|
else:
|
|
933
980
|
current.status = "error"
|
|
934
981
|
current.error = f"Quick Start process exited unexpectedly (code {exit_code})"
|
|
@@ -936,6 +983,7 @@ def _watch_quickstart_process(quickstart_id: str) -> None:
|
|
|
936
983
|
**_stage_event("clone", "error", current.error, terminal=True),
|
|
937
984
|
"status": "error",
|
|
938
985
|
}
|
|
986
|
+
_record_quickstart_end(quickstart_id, "error", error=current.error)
|
|
939
987
|
|
|
940
988
|
|
|
941
989
|
def _cleanup_quickstart_op(operation: QuickstartOperation, *, force: bool) -> None:
|
|
@@ -1098,10 +1146,12 @@ async def start_quickstart() -> QuickstartStartResponse:
|
|
|
1098
1146
|
terminal_event_path=_terminal_event_path(quickstart_id),
|
|
1099
1147
|
)
|
|
1100
1148
|
_quickstart_ops[quickstart_id] = op
|
|
1149
|
+
_record_quickstart_start(quickstart_id)
|
|
1101
1150
|
|
|
1102
1151
|
try:
|
|
1103
1152
|
proc.start()
|
|
1104
|
-
except Exception:
|
|
1153
|
+
except Exception as exc:
|
|
1154
|
+
_record_quickstart_end(quickstart_id, "error", error=str(exc))
|
|
1105
1155
|
_quickstart_ops.pop(quickstart_id, None)
|
|
1106
1156
|
_delete_quickstart_project(previous_default_project)
|
|
1107
1157
|
raise
|
|
@@ -1139,6 +1189,7 @@ async def quickstart_progress(quickstart_id: str):
|
|
|
1139
1189
|
if op.status in {"completed", "error", "cancelled"} and op.last_event:
|
|
1140
1190
|
_cleanup_op(op, force=True)
|
|
1141
1191
|
last_event = op.last_event
|
|
1192
|
+
_record_quickstart_event_end(quickstart_id, last_event)
|
|
1142
1193
|
|
|
1143
1194
|
async def terminal_event():
|
|
1144
1195
|
yield _sse_event(f"quickstart.{last_event['status']}", last_event)
|
|
@@ -1151,6 +1202,7 @@ async def quickstart_progress(quickstart_id: str):
|
|
|
1151
1202
|
while not shutdown_event.is_set():
|
|
1152
1203
|
if op.status in {"completed", "error", "cancelled"}:
|
|
1153
1204
|
if op.last_event is not None:
|
|
1205
|
+
_record_quickstart_event_end(quickstart_id, op.last_event)
|
|
1154
1206
|
yield _sse_event(
|
|
1155
1207
|
f"quickstart.{op.last_event['status']}", op.last_event
|
|
1156
1208
|
)
|
|
@@ -1175,6 +1227,7 @@ async def quickstart_progress(quickstart_id: str):
|
|
|
1175
1227
|
op.last_event = event
|
|
1176
1228
|
if evt_status == "error":
|
|
1177
1229
|
op.error = str(event.get("message") or "Quick Start failed")
|
|
1230
|
+
_record_quickstart_event_end(quickstart_id, event)
|
|
1178
1231
|
break
|
|
1179
1232
|
|
|
1180
1233
|
now = time.time()
|
|
@@ -1192,26 +1245,34 @@ async def quickstart_progress(quickstart_id: str):
|
|
|
1192
1245
|
# TD-3192: SIGTERM-handler exit (143) — clean
|
|
1193
1246
|
# cancel / shutdown, not a crash.
|
|
1194
1247
|
op.status = "cancelled"
|
|
1248
|
+
op.last_event = {
|
|
1249
|
+
**_stage_event(
|
|
1250
|
+
"clone", "cancelled", "Quick Start cancelled"
|
|
1251
|
+
),
|
|
1252
|
+
"status": "cancelled",
|
|
1253
|
+
}
|
|
1254
|
+
_record_quickstart_end(quickstart_id, "cancelled")
|
|
1195
1255
|
yield _sse_event(
|
|
1196
1256
|
"quickstart.cancelled",
|
|
1197
|
-
|
|
1198
|
-
**_stage_event(
|
|
1199
|
-
"clone", "cancelled", "Quick Start cancelled"
|
|
1200
|
-
),
|
|
1201
|
-
"status": "cancelled",
|
|
1202
|
-
},
|
|
1257
|
+
op.last_event,
|
|
1203
1258
|
)
|
|
1204
1259
|
else:
|
|
1205
1260
|
op.status = "error"
|
|
1206
1261
|
op.error = (
|
|
1207
1262
|
f"Quick Start process exited unexpectedly (code {exit_code})"
|
|
1208
1263
|
)
|
|
1264
|
+
op.last_event = {
|
|
1265
|
+
**_stage_event("clone", "error", op.error),
|
|
1266
|
+
"status": "error",
|
|
1267
|
+
}
|
|
1268
|
+
_record_quickstart_end(
|
|
1269
|
+
quickstart_id,
|
|
1270
|
+
"error",
|
|
1271
|
+
error=op.error,
|
|
1272
|
+
)
|
|
1209
1273
|
yield _sse_event(
|
|
1210
1274
|
"quickstart.error",
|
|
1211
|
-
|
|
1212
|
-
**_stage_event("clone", "error", op.error),
|
|
1213
|
-
"status": "error",
|
|
1214
|
-
},
|
|
1275
|
+
op.last_event,
|
|
1215
1276
|
)
|
|
1216
1277
|
break
|
|
1217
1278
|
finally:
|
|
@@ -1298,6 +1359,7 @@ async def cancel_quickstart(quickstart_id: str):
|
|
|
1298
1359
|
}
|
|
1299
1360
|
if op.terminal_event_path is not None:
|
|
1300
1361
|
_persist_terminal_event(op.terminal_event_path, op.last_event)
|
|
1362
|
+
_record_quickstart_end(quickstart_id, "cancelled")
|
|
1301
1363
|
_delete_quickstart_project(op.previous_default_project)
|
|
1302
1364
|
_cleanup_quickstart_op(op, force=True)
|
|
1303
1365
|
return {"message": f"Cancelled Quick Start '{quickstart_id}'"}
|
|
@@ -1053,6 +1053,8 @@ async def start_clone(req: CloneRequest):
|
|
|
1053
1053
|
# repeat call with a different ``project_name`` (now reused as
|
|
1054
1054
|
# ``display_name``) won't clobber the existing entry's display name.
|
|
1055
1055
|
if dest.exists() and any(dest.iterdir()):
|
|
1056
|
+
from core.observability.manifest import record_op_end, record_op_start
|
|
1057
|
+
|
|
1056
1058
|
_register_repo_pool_entry(req.git_url, dest, sanitized)
|
|
1057
1059
|
_clone_ops[clone_id] = {
|
|
1058
1060
|
"status": "complete",
|
|
@@ -1061,8 +1063,17 @@ async def start_clone(req: CloneRequest):
|
|
|
1061
1063
|
"project_name": sanitized,
|
|
1062
1064
|
"error": None,
|
|
1063
1065
|
}
|
|
1066
|
+
record_op_start(
|
|
1067
|
+
"setup",
|
|
1068
|
+
"clone",
|
|
1069
|
+
clone_id,
|
|
1070
|
+
attrs={"project_name": sanitized},
|
|
1071
|
+
)
|
|
1072
|
+
record_op_end("clone", clone_id, "ok")
|
|
1064
1073
|
return CloneResponse(clone_id=clone_id)
|
|
1065
1074
|
|
|
1075
|
+
from core.observability.manifest import record_op_start
|
|
1076
|
+
|
|
1066
1077
|
_clone_ops[clone_id] = {
|
|
1067
1078
|
"status": "pending",
|
|
1068
1079
|
"dest": dest,
|
|
@@ -1070,6 +1081,12 @@ async def start_clone(req: CloneRequest):
|
|
|
1070
1081
|
"project_name": sanitized,
|
|
1071
1082
|
"error": None,
|
|
1072
1083
|
}
|
|
1084
|
+
record_op_start(
|
|
1085
|
+
"setup",
|
|
1086
|
+
"clone",
|
|
1087
|
+
clone_id,
|
|
1088
|
+
attrs={"project_name": sanitized},
|
|
1089
|
+
)
|
|
1073
1090
|
|
|
1074
1091
|
# Spawn clone in background; register pool entry on success.
|
|
1075
1092
|
asyncio.create_task(
|
|
@@ -1186,6 +1203,7 @@ async def _run_clone(
|
|
|
1186
1203
|
project creations against the same URL hit the dedupe path in
|
|
1187
1204
|
:func:`start_clone`.
|
|
1188
1205
|
"""
|
|
1206
|
+
from core.observability.manifest import record_op_end
|
|
1189
1207
|
from lineage.utils.git import clone_repo_with_progress
|
|
1190
1208
|
|
|
1191
1209
|
_clone_ops[clone_id]["status"] = "running"
|
|
@@ -1195,6 +1213,12 @@ async def _run_clone(
|
|
|
1195
1213
|
if progress.phase == "error":
|
|
1196
1214
|
_clone_ops[clone_id]["status"] = "error"
|
|
1197
1215
|
_clone_ops[clone_id]["error"] = progress.message
|
|
1216
|
+
record_op_end(
|
|
1217
|
+
"clone",
|
|
1218
|
+
clone_id,
|
|
1219
|
+
"error",
|
|
1220
|
+
error=progress.message,
|
|
1221
|
+
)
|
|
1198
1222
|
return
|
|
1199
1223
|
_clone_ops[clone_id]["status"] = "complete"
|
|
1200
1224
|
try:
|
|
@@ -1205,9 +1229,11 @@ async def _run_clone(
|
|
|
1205
1229
|
url,
|
|
1206
1230
|
exc,
|
|
1207
1231
|
)
|
|
1232
|
+
record_op_end("clone", clone_id, "ok")
|
|
1208
1233
|
except Exception as exc:
|
|
1209
1234
|
_clone_ops[clone_id]["status"] = "error"
|
|
1210
1235
|
_clone_ops[clone_id]["error"] = str(exc)
|
|
1236
|
+
record_op_end("clone", clone_id, "error", error=str(exc))
|
|
1211
1237
|
|
|
1212
1238
|
|
|
1213
1239
|
@router.get("/clone/{clone_id}/progress")
|
|
@@ -4213,6 +4239,33 @@ async def _create_project(
|
|
|
4213
4239
|
_preflight_clone_locks: dict[str, asyncio.Lock] = {}
|
|
4214
4240
|
|
|
4215
4241
|
|
|
4242
|
+
def _preview_preflight_manifest_outcome(
|
|
4243
|
+
last_event: str | None,
|
|
4244
|
+
) -> tuple[Literal["ok", "error", "cancelled"], str | None]:
|
|
4245
|
+
if last_event is None:
|
|
4246
|
+
return "cancelled", None
|
|
4247
|
+
event_type: str | None = None
|
|
4248
|
+
payload: dict[str, Any] = {}
|
|
4249
|
+
for line in last_event.splitlines():
|
|
4250
|
+
if line.startswith("event: "):
|
|
4251
|
+
event_type = line[len("event: ") :]
|
|
4252
|
+
elif line.startswith("data: "):
|
|
4253
|
+
try:
|
|
4254
|
+
parsed = json.loads(line[len("data: ") :])
|
|
4255
|
+
except json.JSONDecodeError:
|
|
4256
|
+
parsed = {}
|
|
4257
|
+
if isinstance(parsed, dict):
|
|
4258
|
+
payload = parsed
|
|
4259
|
+
if event_type is None:
|
|
4260
|
+
return "cancelled", None
|
|
4261
|
+
if event_type.endswith(".done"):
|
|
4262
|
+
return "ok", None
|
|
4263
|
+
if event_type.endswith(".error"):
|
|
4264
|
+
message = payload.get("message")
|
|
4265
|
+
return "error", message if isinstance(message, str) else None
|
|
4266
|
+
return "cancelled", None
|
|
4267
|
+
|
|
4268
|
+
|
|
4216
4269
|
async def _run_preflight_sse(
|
|
4217
4270
|
*,
|
|
4218
4271
|
adapter: str,
|
|
@@ -4701,6 +4754,18 @@ async def start_preview_preflight(req: PreviewPreflightRequest):
|
|
|
4701
4754
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
4702
4755
|
|
|
4703
4756
|
async def generate():
|
|
4757
|
+
from core.observability.manifest import record_op_end, record_op_start
|
|
4758
|
+
|
|
4759
|
+
record_op_start(
|
|
4760
|
+
"setup",
|
|
4761
|
+
"wizard_preflight",
|
|
4762
|
+
req.session_id,
|
|
4763
|
+
attrs={
|
|
4764
|
+
"backend": req.backend,
|
|
4765
|
+
"project_name": sanitized,
|
|
4766
|
+
},
|
|
4767
|
+
)
|
|
4768
|
+
last_event: str | None = None
|
|
4704
4769
|
tmp_profiles_dir = Path(tempfile.mkdtemp(prefix="typedef-preview-preflight-"))
|
|
4705
4770
|
try:
|
|
4706
4771
|
shutil.rmtree(scratch_root, ignore_errors=True)
|
|
@@ -4726,8 +4791,16 @@ async def start_preview_preflight(req: PreviewPreflightRequest):
|
|
|
4726
4791
|
and req.snowflake_inject_secondary_roles
|
|
4727
4792
|
),
|
|
4728
4793
|
):
|
|
4794
|
+
last_event = event
|
|
4729
4795
|
yield event
|
|
4730
4796
|
finally:
|
|
4797
|
+
outcome, error = _preview_preflight_manifest_outcome(last_event)
|
|
4798
|
+
record_op_end(
|
|
4799
|
+
"wizard_preflight",
|
|
4800
|
+
req.session_id,
|
|
4801
|
+
outcome,
|
|
4802
|
+
error=error,
|
|
4803
|
+
)
|
|
4731
4804
|
shutil.rmtree(tmp_profiles_dir, ignore_errors=True)
|
|
4732
4805
|
|
|
4733
4806
|
return StreamingResponse(generate(), media_type="text/event-stream")
|
|
@@ -25,6 +25,8 @@ 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.observability import Outcome
|
|
29
|
+
from core.observability.manifest import record_op_end, record_op_start
|
|
28
30
|
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
29
31
|
from lineage.api.posthog_analytics import (
|
|
30
32
|
backend_event_insert_id,
|
|
@@ -247,6 +249,7 @@ class SyncOperation:
|
|
|
247
249
|
# loops cleanly.
|
|
248
250
|
subscribers: set[Any] = field(default_factory=set)
|
|
249
251
|
drain_task: Any | None = None
|
|
252
|
+
sync_project_started: set[str] = field(default_factory=set)
|
|
250
253
|
|
|
251
254
|
|
|
252
255
|
@dataclass(frozen=True)
|
|
@@ -273,6 +276,76 @@ _sync_lock = threading.Lock()
|
|
|
273
276
|
_op_state_lock = threading.Lock()
|
|
274
277
|
|
|
275
278
|
|
|
279
|
+
def _sync_manifest_attrs(op: SyncOperation) -> dict[str, str]:
|
|
280
|
+
return {"workspace_name": op.workspace_name, "project_name": op.project_name}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _sync_project_manifest_attrs(project_name: str) -> dict[str, str]:
|
|
284
|
+
return {"project_name": project_name}
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _sync_outcome(status: str | None) -> Outcome:
|
|
288
|
+
if status == "error":
|
|
289
|
+
return "error"
|
|
290
|
+
if status == "cancelled":
|
|
291
|
+
return "cancelled"
|
|
292
|
+
return "ok"
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def _sync_project_op_id(sync_id: str, project_name: str) -> str:
|
|
296
|
+
return f"{sync_id}/{project_name}"
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _record_sync_start(op: SyncOperation) -> None:
|
|
300
|
+
record_op_start("sync", "sync", op.sync_id, attrs=_sync_manifest_attrs(op))
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _record_sync_end(
|
|
304
|
+
sync_id: str,
|
|
305
|
+
outcome: Outcome,
|
|
306
|
+
*,
|
|
307
|
+
error: str | None = None,
|
|
308
|
+
) -> None:
|
|
309
|
+
record_op_end("sync", sync_id, outcome, error=error)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _record_sync_event_end(sync_id: str, event: dict[str, Any]) -> None:
|
|
313
|
+
status = event.get("status")
|
|
314
|
+
outcome = _sync_outcome(str(status) if status is not None else None)
|
|
315
|
+
error = str(event.get("message") or "Sync failed") if outcome == "error" else None
|
|
316
|
+
_record_sync_end(sync_id, outcome, error=error)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def _record_sync_project_start(op: SyncOperation, project_name: str) -> None:
|
|
320
|
+
if project_name in op.sync_project_started:
|
|
321
|
+
return
|
|
322
|
+
op.sync_project_started.add(project_name)
|
|
323
|
+
record_op_start(
|
|
324
|
+
"sync",
|
|
325
|
+
"sync_project",
|
|
326
|
+
_sync_project_op_id(op.sync_id, project_name),
|
|
327
|
+
parent_op_id=op.sync_id,
|
|
328
|
+
attrs=_sync_project_manifest_attrs(project_name),
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def _record_sync_project_end(
|
|
333
|
+
op: SyncOperation,
|
|
334
|
+
project_name: str,
|
|
335
|
+
outcome: Outcome,
|
|
336
|
+
*,
|
|
337
|
+
error: str | None = None,
|
|
338
|
+
artifacts: list[str] | None = None,
|
|
339
|
+
) -> None:
|
|
340
|
+
record_op_end(
|
|
341
|
+
"sync_project",
|
|
342
|
+
_sync_project_op_id(op.sync_id, project_name),
|
|
343
|
+
outcome,
|
|
344
|
+
error=error,
|
|
345
|
+
artifacts=artifacts or [],
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
|
|
276
349
|
def _get_sync_op(sync_id: str) -> SyncOperation | None:
|
|
277
350
|
"""Read a sync operation from the registry under the module lock."""
|
|
278
351
|
with _sync_lock:
|
|
@@ -580,12 +653,26 @@ async def _drain_op_queue(op: SyncOperation) -> None:
|
|
|
580
653
|
|
|
581
654
|
if event is not None:
|
|
582
655
|
evt_status = event.get("status", "running")
|
|
656
|
+
project_name = event.get("project")
|
|
657
|
+
if isinstance(project_name, str) and project_name:
|
|
658
|
+
_record_sync_project_start(op, project_name)
|
|
659
|
+
if event.get("stage") == "project_error":
|
|
660
|
+
_record_sync_project_end(
|
|
661
|
+
op,
|
|
662
|
+
project_name,
|
|
663
|
+
"error",
|
|
664
|
+
error=str(event.get("message") or "sync failed"),
|
|
665
|
+
)
|
|
583
666
|
# TD-3196: per-project completion inside a workspace build —
|
|
584
667
|
# persist THIS project's synced commit + build state (keyed on
|
|
585
668
|
# the event's ``project``), non-terminal so the batch's other
|
|
586
669
|
# projects + the final L1 pass keep streaming.
|
|
587
670
|
if event.get("stage") == "project_complete":
|
|
588
|
-
_proj =
|
|
671
|
+
_proj = (
|
|
672
|
+
project_name
|
|
673
|
+
if isinstance(project_name, str) and project_name
|
|
674
|
+
else op.project_name
|
|
675
|
+
)
|
|
589
676
|
try:
|
|
590
677
|
await asyncio.to_thread(
|
|
591
678
|
_persist_synced_commit,
|
|
@@ -639,6 +726,12 @@ async def _drain_op_queue(op: SyncOperation) -> None:
|
|
|
639
726
|
"failed for %s",
|
|
640
727
|
_proj,
|
|
641
728
|
)
|
|
729
|
+
_record_sync_project_end(
|
|
730
|
+
op,
|
|
731
|
+
_proj,
|
|
732
|
+
"ok",
|
|
733
|
+
artifacts=[str(v) for v in (event.get("artifacts") or [])],
|
|
734
|
+
)
|
|
642
735
|
_record_and_broadcast(op, event)
|
|
643
736
|
last_heartbeat = time.time()
|
|
644
737
|
continue
|
|
@@ -707,6 +800,7 @@ async def _drain_op_queue(op: SyncOperation) -> None:
|
|
|
707
800
|
"[desktop:sync] _persist_target_build_state failed for %s",
|
|
708
801
|
op.project_name,
|
|
709
802
|
)
|
|
803
|
+
_record_sync_event_end(op.sync_id, event)
|
|
710
804
|
_record_and_broadcast(op, event)
|
|
711
805
|
if evt_status in ("completed", "error", "cancelled"):
|
|
712
806
|
break
|
|
@@ -739,6 +833,7 @@ async def _drain_op_queue(op: SyncOperation) -> None:
|
|
|
739
833
|
"total": 0,
|
|
740
834
|
},
|
|
741
835
|
)
|
|
836
|
+
_record_sync_end(op.sync_id, "cancelled")
|
|
742
837
|
else:
|
|
743
838
|
op.status = "error"
|
|
744
839
|
op.error = f"Sync process exited unexpectedly (code {exit_code})"
|
|
@@ -752,6 +847,7 @@ async def _drain_op_queue(op: SyncOperation) -> None:
|
|
|
752
847
|
"total": 0,
|
|
753
848
|
},
|
|
754
849
|
)
|
|
850
|
+
_record_sync_end(op.sync_id, "error", error=op.error)
|
|
755
851
|
break
|
|
756
852
|
finally:
|
|
757
853
|
# Tell every subscriber the stream is finished — they break
|
|
@@ -815,6 +911,7 @@ def _reap_dead_op_if_stale(op: SyncOperation) -> bool:
|
|
|
815
911
|
op.sync_id,
|
|
816
912
|
exc_info=True,
|
|
817
913
|
)
|
|
914
|
+
_record_sync_end(op.sync_id, "error", error=op.error)
|
|
818
915
|
_pop_sync_op(op.sync_id)
|
|
819
916
|
return True
|
|
820
917
|
|
|
@@ -2353,7 +2450,7 @@ def _maybe_migrate_workspace_graph(
|
|
|
2353
2450
|
"stage": "migrate",
|
|
2354
2451
|
"current": current,
|
|
2355
2452
|
"total": total,
|
|
2356
|
-
"status": "running"
|
|
2453
|
+
"status": "running",
|
|
2357
2454
|
"message": f"Upgrading lineage graph: {stage}",
|
|
2358
2455
|
}
|
|
2359
2456
|
)
|
|
@@ -2370,7 +2467,7 @@ def _maybe_migrate_workspace_graph(
|
|
|
2370
2467
|
"stage": "migrate",
|
|
2371
2468
|
"current": cleared,
|
|
2372
2469
|
"total": cleared,
|
|
2373
|
-
"status": "
|
|
2470
|
+
"status": "running",
|
|
2374
2471
|
"message": (
|
|
2375
2472
|
f"Lineage graph upgraded "
|
|
2376
2473
|
f"({cleared} context entr{'y' if cleared == 1 else 'ies'} "
|
|
@@ -2470,12 +2567,25 @@ def _build_one_project(
|
|
|
2470
2567
|
from ingest.unified.stages.registry import get_stage_label
|
|
2471
2568
|
from ingest.unified.stages.types import UnifiedPipelineConfig
|
|
2472
2569
|
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2570
|
+
try:
|
|
2571
|
+
config = UnifiedPipelineConfig.from_project_name(
|
|
2572
|
+
project_name,
|
|
2573
|
+
workspace_name=workspace_name,
|
|
2574
|
+
full=full,
|
|
2575
|
+
llm_proxy=llm_proxy,
|
|
2576
|
+
)
|
|
2577
|
+
except ValueError as exc:
|
|
2578
|
+
# TD-3823: a project's authored settings can fail integration-config
|
|
2579
|
+
# validation (e.g. airflow.rtif_k_runs outside the reader's ceiling).
|
|
2580
|
+
# This must stay a per-project failure — not caught here, it propagates
|
|
2581
|
+
# past this function's own try/except below (which only wraps
|
|
2582
|
+
# orchestrator.run()) straight out of the per-project loop in
|
|
2583
|
+
# _sync_worker and aborts the WHOLE workspace batch, contradicting this
|
|
2584
|
+
# function's own "per-project failures are non-fatal" contract.
|
|
2585
|
+
log.exception("[%s] config parsing failed", project_name)
|
|
2586
|
+
_capture_sync_failed_analytics(llm_proxy, analytics_context, sync_id, exc)
|
|
2587
|
+
return _ProjectOutcome(status="error", error=str(exc) or type(exc).__name__)
|
|
2588
|
+
|
|
2479
2589
|
_apply_sync_run_overrides(config, run_overrides or SyncRunOverrides())
|
|
2480
2590
|
# TD-3196: in a multi-project workspace build, skip the workspace-global
|
|
2481
2591
|
# L1 concept rebuild on each per-project sync; the coordinator runs one
|
|
@@ -2562,6 +2672,7 @@ def _build_one_project(
|
|
|
2562
2672
|
"total": total,
|
|
2563
2673
|
"status": "running",
|
|
2564
2674
|
"message": get_stage_label(stage_name),
|
|
2675
|
+
"project": project_name,
|
|
2565
2676
|
**_outer,
|
|
2566
2677
|
}
|
|
2567
2678
|
)
|
|
@@ -2576,6 +2687,7 @@ def _build_one_project(
|
|
|
2576
2687
|
"total": 0,
|
|
2577
2688
|
"status": "running",
|
|
2578
2689
|
"message": "Starting sync pipeline",
|
|
2690
|
+
"project": project_name,
|
|
2579
2691
|
**_outer,
|
|
2580
2692
|
}
|
|
2581
2693
|
)
|
|
@@ -2913,6 +3025,7 @@ def _sync_worker(
|
|
|
2913
3025
|
"total": 0,
|
|
2914
3026
|
"status": "running",
|
|
2915
3027
|
"message": f"{spec.name}: {outcome.error or 'sync failed'}",
|
|
3028
|
+
"project": spec.name,
|
|
2916
3029
|
"outer_label": outer[0],
|
|
2917
3030
|
"outer_current": outer[1],
|
|
2918
3031
|
"outer_total": outer[2],
|
|
@@ -3523,11 +3636,17 @@ async def start_sync(req: SyncRequest, request: Request):
|
|
|
3523
3636
|
started_at=time.time(),
|
|
3524
3637
|
)
|
|
3525
3638
|
_sync_ops[sync_id] = op
|
|
3639
|
+
_record_sync_start(op)
|
|
3526
3640
|
|
|
3527
3641
|
# TD-3192: start the process INSIDE the lock so the shutdown
|
|
3528
3642
|
# snapshot can't observe a registered-but-not-started op (which
|
|
3529
3643
|
# would have a ``None`` pid and escape termination).
|
|
3530
|
-
|
|
3644
|
+
try:
|
|
3645
|
+
proc.start()
|
|
3646
|
+
except Exception as exc:
|
|
3647
|
+
_record_sync_end(sync_id, "error", error=str(exc))
|
|
3648
|
+
_sync_ops.pop(sync_id, None)
|
|
3649
|
+
raise
|
|
3531
3650
|
|
|
3532
3651
|
logger.info(
|
|
3533
3652
|
"[desktop:sync] Started sync %s for project '%s' (pid=%d)",
|
|
@@ -3671,6 +3790,7 @@ async def cancel_sync(sync_id: str):
|
|
|
3671
3790
|
pass # nosec B110 — best-effort queue teardown
|
|
3672
3791
|
|
|
3673
3792
|
op.status = "cancelled"
|
|
3793
|
+
_record_sync_end(sync_id, "cancelled")
|
|
3674
3794
|
logger.info("[desktop:sync] Cancelled sync %s", sync_id)
|
|
3675
3795
|
|
|
3676
3796
|
# Remove from registry after brief delay
|