Skip to content

feat(handler): /workflows/v1/input-contract + default entrypoint resolution#1965

Open
OnkarVO7 wants to merge 7 commits into
mainfrom
onkarravgan/bldx-1354
Open

feat(handler): /workflows/v1/input-contract + default entrypoint resolution#1965
OnkarVO7 wants to merge 7 commits into
mainfrom
onkarravgan/bldx-1354

Conversation

@OnkarVO7
Copy link
Copy Markdown
Collaborator

@OnkarVO7 OnkarVO7 commented Jun 2, 2026

Changelog

  • Add GET /workflows/v1/input-contract — returns the resolved entrypoint's AppInputContract.model_json_schema() (the same Pydantic model /workflows/v1/start validates against). The orchestrator (Heracles) consumes it to validate request inputs and to detect credential fields by the CredentialRef/AgentCredentialSpec $ref.
  • Add default-entrypoint support: @entrypoint(default=True) + EntryPointMetadata.default, and a resolve_default_entrypoint() helper. Registration rejects more than one default.
  • /workflows/v1/start and /workflows/v1/input-contract both resolve the default when ?entrypoint= is omitted, so they behave consistently.
  • Allow run() and @entrypoint-decorated methods to coexist in the same App subclass. run() always holds permanent default-precedence in mixed apps; using @entrypoint(default=True) alongside run() is an error. Multiple @entrypoints with no explicit default auto-mark the first alphabetically as default.
  • No behavior change for existing apps: single-entrypoint (run()-only) apps are backward-compatible. Multi-entrypoint apps without any explicit default now get an auto-default (first alphabetically) rather than 400ing; apps that previously 400'd on /input-contract without ?entrypoint= will now resolve.

Entrypoint registration rules

App shape Default resolution
run() only run() is the implicit default (backward compat)
Single @entrypoint that entry point is the default (len==1 rule)
Multiple @entrypoints, none explicit first alphabetically is auto-marked default
Multiple @entrypoints, one default=True that one is the default
Multiple @entrypoints, multiple default=True error at class definition time
run() + @entrypoint(s) run() is always the default; @entrypoint(default=True) raises

Additional context (e.g. screenshots, logs, links)

  • Part of BLDX-1354 — native app workflow APIs (app-contract-driven, Argo-free). This is the app-SDK half; the Heracles /v1/app/* consumer lands separately.
  • Design doc: heracles/docs/v2-native-workflow-apis-plan.md.

Checklist

  • Additional tests added (8 registration scenarios + full handler invocability matrix)
  • All CI checks passed
  • Relevant documentation updated

Copyleft License Compliance

  • Have you used any code that is subject to a Copyleft license (e.g., GPL, AGPL, LGPL)?
  • If yes, have you modified the code in the context of this project? please share additional details.

🤖 Generated with Claude Code

@snykgituser
Copy link
Copy Markdown

snykgituser commented Jun 2, 2026

Snyk checks have failed. 1 issues have been found so far.

Status Scan Engine Critical High Medium Low Total (1)
Code Security 0 1 0 0 1 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

📜 Docstring Coverage Report

RESULT: PASSED (minimum: 30.0%, actual: 77.6%)

Detailed Coverage Report
======= Coverage for /home/runner/work/application-sdk/application-sdk/ ========
----------------------------------- Summary ------------------------------------
| Name                                                                           | Total | Miss | Cover | Cover% |
|--------------------------------------------------------------------------------|-------|------|-------|--------|
| .claude/skills/capability-manifest/references/extractor.py                     |    21 |    2 |    19 |    90% |
| .mothership/sdk-evolution/scripts/update_index.py                              |    10 |    2 |     8 |    80% |
| application_sdk/__init__.py                                                    |     1 |    0 |     1 |   100% |
| application_sdk/_discovery_errors.py                                           |     7 |    0 |     7 |   100% |
| application_sdk/constants.py                                                   |     3 |    1 |     2 |    67% |
| application_sdk/discovery.py                                                   |    12 |    3 |     9 |    75% |
| application_sdk/main.py                                                        |    31 |    6 |    25 |    81% |
| application_sdk/main_errors.py                                                 |     5 |    0 |     5 |   100% |
| application_sdk/version.py                                                     |     1 |    0 |     1 |   100% |
| application_sdk/app/__init__.py                                                |     1 |    0 |     1 |   100% |
| application_sdk/app/_ep_registration.py                                        |     6 |    0 |     6 |   100% |
| application_sdk/app/base.py                                                    |    72 |   18 |    54 |    75% |
| application_sdk/app/base_errors.py                                             |     5 |    0 |     5 |   100% |
| application_sdk/app/client.py                                                  |     1 |    0 |     1 |   100% |
| application_sdk/app/context.py                                                 |    39 |    2 |    37 |    95% |
| application_sdk/app/entrypoint.py                                              |    14 |    4 |    10 |    71% |
| application_sdk/app/registry.py                                                |    37 |   11 |    26 |    70% |
| application_sdk/app/task.py                                                    |    14 |    6 |     8 |    57% |
| application_sdk/clients/__init__.py                                            |     2 |    1 |     1 |    50% |
| application_sdk/clients/_interface.py                                          |     4 |    1 |     3 |    75% |
| application_sdk/clients/base.py                                                |     6 |    1 |     5 |    83% |
| application_sdk/clients/models.py                                              |     2 |    0 |     2 |   100% |
| application_sdk/clients/redis.py                                               |    27 |    0 |    27 |   100% |
| application_sdk/clients/redis_errors.py                                        |     5 |    0 |     5 |   100% |
| application_sdk/clients/sql.py                                                 |    23 |    1 |    22 |    96% |
| application_sdk/clients/sql_errors.py                                          |    11 |    0 |    11 |   100% |
| application_sdk/clients/sql_typecasters.py                                     |    10 |    4 |     6 |    60% |
| application_sdk/clients/ssl_utils.py                                           |     8 |    0 |     8 |   100% |
| application_sdk/clients/azure/__init__.py                                      |     1 |    0 |     1 |   100% |
| application_sdk/clients/azure/auth.py                                          |     7 |    0 |     7 |   100% |
| application_sdk/clients/azure/azure_errors.py                                  |     8 |    0 |     8 |   100% |
| application_sdk/clients/azure/client.py                                        |    13 |    0 |    13 |   100% |
| application_sdk/common/__init__.py                                             |     1 |    0 |     1 |   100% |
| application_sdk/common/_env.py                                                 |     2 |    0 |     2 |   100% |
| application_sdk/common/aws_utils.py                                            |    10 |    1 |     9 |    90% |
| application_sdk/common/aws_utils_errors.py                                     |     7 |    0 |     7 |   100% |
| application_sdk/common/concurrency.py                                          |     3 |    0 |     3 |   100% |
| application_sdk/common/env_warnings.py                                         |     2 |    0 |     2 |   100% |
| application_sdk/common/error_codes.py                                          |    15 |    3 |    12 |    80% |
| application_sdk/common/errors.py                                               |     6 |    0 |     6 |   100% |
| application_sdk/common/file_converter.py                                       |     9 |    5 |     4 |    44% |
| application_sdk/common/file_ops.py                                             |    16 |    1 |    15 |    94% |
| application_sdk/common/models.py                                               |     4 |    2 |     2 |    50% |
| application_sdk/common/path.py                                                 |     2 |    1 |     1 |    50% |
| application_sdk/common/spillable_dict.py                                       |    17 |   11 |     6 |    35% |
| application_sdk/common/sql_filters.py                                          |    13 |    1 |    12 |    92% |
| application_sdk/common/sql_filters_errors.py                                   |     2 |    0 |     2 |   100% |
| application_sdk/common/transforms.py                                           |     5 |    0 |     5 |   100% |
| application_sdk/common/types.py                                                |     2 |    1 |     1 |    50% |
| application_sdk/common/utils.py                                                |     2 |    0 |     2 |   100% |
| application_sdk/common/incremental/__init__.py                                 |     1 |    1 |     0 |     0% |
| application_sdk/common/incremental/helpers.py                                  |    12 |    1 |    11 |    92% |
| application_sdk/common/incremental/incremental_errors.py                       |    11 |    0 |    11 |   100% |
| application_sdk/common/incremental/marker.py                                   |     5 |    0 |     5 |   100% |
| application_sdk/common/incremental/models.py                                   |    10 |    0 |    10 |   100% |
| application_sdk/common/incremental/column_extraction/__init__.py               |     1 |    0 |     1 |   100% |
| application_sdk/common/incremental/column_extraction/analysis.py               |     3 |    0 |     3 |   100% |
| application_sdk/common/incremental/column_extraction/backfill.py               |     3 |    0 |     3 |   100% |
| application_sdk/common/incremental/state/__init__.py                           |     1 |    1 |     0 |     0% |
| application_sdk/common/incremental/state/incremental_diff.py                   |     8 |    0 |     8 |   100% |
| application_sdk/common/incremental/state/state_reader.py                       |     2 |    0 |     2 |   100% |
| application_sdk/common/incremental/state/state_writer.py                       |    10 |    0 |    10 |   100% |
| application_sdk/common/incremental/state/table_scope.py                        |     8 |    0 |     8 |   100% |
| application_sdk/common/incremental/storage/__init__.py                         |     1 |    1 |     0 |     0% |
| application_sdk/common/incremental/storage/duckdb_utils.py                     |    12 |    2 |    10 |    83% |
| application_sdk/common/incremental/storage/rocksdb_utils.py                    |     3 |    0 |     3 |   100% |
| application_sdk/contracts/__init__.py                                          |     1 |    0 |     1 |   100% |
| application_sdk/contracts/base.py                                              |    37 |    7 |    30 |    81% |
| application_sdk/contracts/cleanup.py                                           |     5 |    0 |     5 |   100% |
| application_sdk/contracts/events.py                                            |    12 |    0 |    12 |   100% |
| application_sdk/contracts/storage.py                                           |     6 |    1 |     5 |    83% |
| application_sdk/contracts/types.py                                             |    15 |    0 |    15 |   100% |
| application_sdk/contracts/types_errors.py                                      |     2 |    0 |     2 |   100% |
| application_sdk/credentials/__init__.py                                        |     1 |    0 |     1 |   100% |
| application_sdk/credentials/agent.py                                           |     7 |    1 |     6 |    86% |
| application_sdk/credentials/atlan.py                                           |    12 |    6 |     6 |    50% |
| application_sdk/credentials/atlan_client.py                                    |     6 |    0 |     6 |   100% |
| application_sdk/credentials/errors.py                                          |    20 |   12 |     8 |    40% |
| application_sdk/credentials/git.py                                             |     9 |    6 |     3 |    33% |
| application_sdk/credentials/oauth.py                                           |    13 |    2 |    11 |    85% |
| application_sdk/credentials/ref.py                                             |    16 |    1 |    15 |    94% |
| application_sdk/credentials/registry.py                                        |    11 |    3 |     8 |    73% |
| application_sdk/credentials/resolver.py                                        |    11 |    4 |     7 |    64% |
| application_sdk/credentials/spec.py                                            |     6 |    1 |     5 |    83% |
| application_sdk/credentials/types.py                                           |    35 |   17 |    18 |    51% |
| application_sdk/credentials/utils.py                                           |     3 |    0 |     3 |   100% |
| application_sdk/dev/__init__.py                                                |     1 |    0 |     1 |   100% |
| application_sdk/dev/_dapr.py                                                   |    11 |    2 |     9 |    82% |
| application_sdk/dev/_dapr_errors.py                                            |     5 |    4 |     1 |    20% |
| application_sdk/dev/_embedded.py                                               |     3 |    0 |     3 |   100% |
| application_sdk/errors/__init__.py                                             |     4 |    1 |     3 |    75% |
| application_sdk/errors/base.py                                                 |     8 |    2 |     6 |    75% |
| application_sdk/errors/categories.py                                           |     3 |    0 |     3 |   100% |
| application_sdk/errors/leaves.py                                               |    15 |    8 |     7 |    47% |
| application_sdk/errors/wire.py                                                 |     3 |    1 |     2 |    67% |
| application_sdk/execution/__init__.py                                          |     1 |    0 |     1 |   100% |
| application_sdk/execution/decorators.py                                        |     3 |    2 |     1 |    33% |
| application_sdk/execution/errors.py                                            |     2 |    0 |     2 |   100% |
| application_sdk/execution/heartbeat.py                                         |    17 |    2 |    15 |    88% |
| application_sdk/execution/retry.py                                             |     7 |    0 |     7 |   100% |
| application_sdk/execution/sandbox.py                                           |     4 |    0 |     4 |   100% |
| application_sdk/execution/settings.py                                          |     6 |    1 |     5 |    83% |
| application_sdk/execution/shutdown.py                                          |     4 |    0 |     4 |   100% |
| application_sdk/execution/_temporal/__init__.py                                |     1 |    1 |     0 |     0% |
| application_sdk/execution/_temporal/_activity_errors.py                        |     7 |    0 |     7 |   100% |
| application_sdk/execution/_temporal/_backend_errors.py                         |     5 |    4 |     1 |    20% |
| application_sdk/execution/_temporal/_lock_errors.py                            |     5 |    0 |     5 |   100% |
| application_sdk/execution/_temporal/activities.py                              |     7 |    0 |     7 |   100% |
| application_sdk/execution/_temporal/activity_utils.py                          |     6 |    0 |     6 |   100% |
| application_sdk/execution/_temporal/auth.py                                    |    12 |    0 |    12 |   100% |
| application_sdk/execution/_temporal/backend.py                                 |    12 |    1 |    11 |    92% |
| application_sdk/execution/_temporal/converter.py                               |     3 |    0 |     3 |   100% |
| application_sdk/execution/_temporal/eviction_retry.py                          |     3 |    0 |     3 |   100% |
| application_sdk/execution/_temporal/lock_activities.py                         |     3 |    0 |     3 |   100% |
| application_sdk/execution/_temporal/sdr.py                                     |    13 |    7 |     6 |    46% |
| application_sdk/execution/_temporal/worker.py                                  |    10 |    5 |     5 |    50% |
| application_sdk/execution/_temporal/workflows.py                               |     2 |    0 |     2 |   100% |
| application_sdk/execution/_temporal/interceptors/__init__.py                   |     1 |    0 |     1 |   100% |
| application_sdk/execution/_temporal/interceptors/events.py                     |    13 |    0 |    13 |   100% |
| application_sdk/execution/_temporal/interceptors/lock.py                       |    10 |    2 |     8 |    80% |
| application_sdk/execution/_temporal/interceptors/log.py                        |    19 |   12 |     7 |    37% |
| application_sdk/execution/_temporal/interceptors/metrics.py                    |    16 |   13 |     3 |    19% |
| application_sdk/execution/_temporal/interceptors/outputs.py                    |     9 |    0 |     9 |   100% |
| application_sdk/execution/_temporal/interceptors/trace.py                      |     6 |    4 |     2 |    33% |
| application_sdk/handler/__init__.py                                            |     1 |    0 |     1 |   100% |
| application_sdk/handler/base.py                                                |    14 |    3 |    11 |    79% |
| application_sdk/handler/context.py                                             |    17 |    5 |    12 |    71% |
| application_sdk/handler/contracts.py                                           |    32 |    3 |    29 |    91% |
| application_sdk/handler/manifest.py                                            |     5 |    0 |     5 |   100% |
| application_sdk/handler/service.py                                             |    48 |   23 |    25 |    52% |
| application_sdk/handler/service_errors.py                                      |     4 |    0 |     4 |   100% |
| application_sdk/infrastructure/__init__.py                                     |     1 |    0 |     1 |   100% |
| application_sdk/infrastructure/_secret_utils.py                                |     2 |    0 |     2 |   100% |
| application_sdk/infrastructure/bindings.py                                     |    16 |    3 |    13 |    81% |
| application_sdk/infrastructure/capacity.py                                     |    11 |    0 |    11 |   100% |
| application_sdk/infrastructure/context.py                                      |     6 |    0 |     6 |   100% |
| application_sdk/infrastructure/credential_vault.py                             |     7 |    3 |     4 |    57% |
| application_sdk/infrastructure/pubsub.py                                       |    13 |    3 |    10 |    77% |
| application_sdk/infrastructure/secrets.py                                      |    21 |    6 |    15 |    71% |
| application_sdk/infrastructure/state.py                                        |    10 |    7 |     3 |    30% |
| application_sdk/infrastructure/_dapr/__init__.py                               |     1 |    0 |     1 |   100% |
| application_sdk/infrastructure/_dapr/_dapr_errors.py                           |     3 |    0 |     3 |   100% |
| application_sdk/infrastructure/_dapr/client.py                                 |    28 |    4 |    24 |    86% |
| application_sdk/infrastructure/_dapr/credential_vault.py                       |    13 |    4 |     9 |    69% |
| application_sdk/infrastructure/_dapr/http.py                                   |    17 |   12 |     5 |    29% |
| application_sdk/infrastructure/_redis/__init__.py                              |     1 |    0 |     1 |   100% |
| application_sdk/infrastructure/_redis/capacity.py                              |     9 |    4 |     5 |    56% |
| application_sdk/observability/__init__.py                                      |     1 |    1 |     0 |     0% |
| application_sdk/observability/_objectstore_metric_exporter.py                  |    13 |    8 |     5 |    38% |
| application_sdk/observability/_objectstore_metric_reader.py                    |     2 |    0 |     2 |   100% |
| application_sdk/observability/_prometheus_enrichment.py                        |     6 |    3 |     3 |    50% |
| application_sdk/observability/context.py                                       |     4 |    0 |     4 |   100% |
| application_sdk/observability/correlation.py                                   |     6 |    0 |     6 |   100% |
| application_sdk/observability/logger_adaptor.py                                |    46 |    8 |    38 |    83% |
| application_sdk/observability/logger_adaptor_errors.py                         |     2 |    0 |     2 |   100% |
| application_sdk/observability/metrics.py                                       |     8 |    6 |     2 |    25% |
| application_sdk/observability/metrics_adaptor.py                               |    13 |    2 |    11 |    85% |
| application_sdk/observability/models.py                                        |     6 |    0 |     6 |   100% |
| application_sdk/observability/observability.py                                 |    19 |    4 |    15 |    79% |
| application_sdk/observability/pushgateway.py                                   |    16 |   11 |     5 |    31% |
| application_sdk/observability/pushgateway_errors.py                            |     3 |    0 |     3 |   100% |
| application_sdk/observability/resource_sampler.py                              |     5 |    0 |     5 |   100% |
| application_sdk/observability/segment_client.py                                |    15 |    1 |    14 |    93% |
| application_sdk/observability/trace_context.py                                 |     2 |    0 |     2 |   100% |
| application_sdk/observability/traces_adaptor.py                                |    15 |    1 |    14 |    93% |
| application_sdk/observability/utils.py                                         |     7 |    1 |     6 |    86% |
| application_sdk/observability/decorators/observability_decorator.py            |     7 |    4 |     3 |    43% |
| application_sdk/outputs/__init__.py                                            |     2 |    0 |     2 |   100% |
| application_sdk/outputs/collector.py                                           |     9 |    0 |     9 |   100% |
| application_sdk/outputs/models.py                                              |     3 |    0 |     3 |   100% |
| application_sdk/server/health.py                                               |    20 |    0 |    20 |   100% |
| application_sdk/server/fastapi/models.py                                       |    21 |   17 |     4 |    19% |
| application_sdk/server/fastapi/utils.py                                        |     5 |    0 |     5 |   100% |
| application_sdk/server/mcp/__init__.py                                         |     2 |    2 |     0 |     0% |
| application_sdk/server/mcp/decorators.py                                       |     3 |    1 |     2 |    67% |
| application_sdk/server/mcp/models.py                                           |     2 |    2 |     0 |     0% |
| application_sdk/server/mcp/server.py                                           |     5 |    0 |     5 |   100% |
| application_sdk/server/middleware/__init__.py                                  |     1 |    0 |     1 |   100% |
| application_sdk/server/middleware/_constants.py                                |     1 |    0 |     1 |   100% |
| application_sdk/server/middleware/log.py                                       |     4 |    3 |     1 |    25% |
| application_sdk/storage/__init__.py                                            |     1 |    0 |     1 |   100% |
| application_sdk/storage/_concurrency.py                                        |     3 |    1 |     2 |    67% |
| application_sdk/storage/_credential_providers.py                               |     3 |    0 |     3 |   100% |
| application_sdk/storage/_obstore_config.py                                     |     8 |    0 |     8 |   100% |
| application_sdk/storage/batch.py                                               |     8 |    2 |     6 |    75% |
| application_sdk/storage/binding.py                                             |    13 |    1 |    12 |    92% |
| application_sdk/storage/cloud.py                                               |    22 |    5 |    17 |    77% |
| application_sdk/storage/errors.py                                              |    29 |   19 |    10 |    34% |
| application_sdk/storage/factory.py                                             |     3 |    0 |     3 |   100% |
| application_sdk/storage/file_ref_sync.py                                       |    13 |    3 |    10 |    77% |
| application_sdk/storage/ops.py                                                 |    21 |    1 |    20 |    95% |
| application_sdk/storage/reference.py                                           |    11 |    1 |    10 |    91% |
| application_sdk/storage/rolling.py                                             |    31 |   12 |    19 |    61% |
| application_sdk/storage/rolling_errors.py                                      |     4 |    0 |     4 |   100% |
| application_sdk/storage/transfer.py                                            |    13 |    3 |    10 |    77% |
| application_sdk/storage/formats/__init__.py                                    |    29 |    0 |    29 |   100% |
| application_sdk/storage/formats/format_errors.py                               |    19 |    0 |    19 |   100% |
| application_sdk/storage/formats/json.py                                        |    15 |    1 |    14 |    93% |
| application_sdk/storage/formats/parquet.py                                     |    28 |    1 |    27 |    96% |
| application_sdk/storage/formats/utils.py                                       |     9 |    2 |     7 |    78% |
| application_sdk/templates/__init__.py                                          |     2 |    1 |     1 |    50% |
| application_sdk/templates/_template_errors.py                                  |     4 |    0 |     4 |   100% |
| application_sdk/templates/base_metadata_extractor.py                           |     4 |    1 |     3 |    75% |
| application_sdk/templates/incremental_sql_metadata_extractor.py                |    18 |    1 |    17 |    94% |
| application_sdk/templates/sql_app.py                                           |    31 |    0 |    31 |   100% |
| application_sdk/templates/sql_app_errors.py                                    |     7 |    0 |     7 |   100% |
| application_sdk/templates/sql_metadata_extractor.py                            |    14 |    1 |    13 |    93% |
| application_sdk/templates/sql_query_extractor.py                               |     6 |    1 |     5 |    83% |
| application_sdk/templates/contracts/__init__.py                                |     1 |    0 |     1 |   100% |
| application_sdk/templates/contracts/base_metadata_extraction.py                |     3 |    0 |     3 |   100% |
| application_sdk/templates/contracts/incremental_sql.py                         |    26 |    5 |    21 |    81% |
| application_sdk/templates/contracts/sql_metadata.py                            |    31 |    8 |    23 |    74% |
| application_sdk/templates/contracts/sql_query.py                               |     7 |    0 |     7 |   100% |
| application_sdk/test_utils/integration/__init__.py                             |     1 |    1 |     0 |     0% |
| application_sdk/testing/__init__.py                                            |     1 |    0 |     1 |   100% |
| application_sdk/testing/fixtures.py                                            |    10 |    0 |    10 |   100% |
| application_sdk/testing/mocks.py                                               |    68 |   17 |    51 |    75% |
| application_sdk/testing/e2e/__init__.py                                        |     1 |    0 |     1 |   100% |
| application_sdk/testing/e2e/_errors.py                                         |    10 |    0 |    10 |   100% |
| application_sdk/testing/e2e/base.py                                            |    18 |    1 |    17 |    94% |
| application_sdk/testing/e2e/client.py                                          |    32 |    6 |    26 |    81% |
| application_sdk/testing/e2e/config.py                                          |     2 |    0 |     2 |   100% |
| application_sdk/testing/e2e/credential.py                                      |     2 |    0 |     2 |   100% |
| application_sdk/testing/e2e/logs.py                                            |     6 |    1 |     5 |    83% |
| application_sdk/testing/e2e/payload.py                                         |     9 |    0 |     9 |   100% |
| application_sdk/testing/e2e/pods.py                                            |     5 |    1 |     4 |    80% |
| application_sdk/testing/e2e/portforward.py                                     |     4 |    0 |     4 |   100% |
| application_sdk/testing/e2e/sql_app.py                                         |     9 |    0 |     9 |   100% |
| application_sdk/testing/e2e/substitutions.py                                   |     3 |    0 |     3 |   100% |
| application_sdk/testing/e2e/workflows.py                                       |     3 |    0 |     3 |   100% |
| application_sdk/testing/full_dag/__init__.py                                   |     1 |    0 |     1 |   100% |
| application_sdk/testing/full_dag/_errors.py                                    |     1 |    0 |     1 |   100% |
| application_sdk/testing/full_dag/base.py                                       |    15 |    1 |    14 |    93% |
| application_sdk/testing/full_dag/client.py                                     |     1 |    0 |     1 |   100% |
| application_sdk/testing/full_dag/payload.py                                    |     8 |    0 |     8 |   100% |
| application_sdk/testing/full_dag/sql_app.py                                    |     5 |    0 |     5 |   100% |
| application_sdk/testing/hypothesis/__init__.py                                 |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/__init__.py                      |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/sql_client.py                    |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/clients/__init__.py              |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/clients/sql.py                   |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/common/__init__.py               |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/common/logger.py                 |     3 |    0 |     3 |   100% |
| application_sdk/testing/hypothesis/strategies/handlers/__init__.py             |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/handlers/sql/__init__.py         |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/handlers/sql/sql_metadata.py     |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/handlers/sql/sql_preflight.py    |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/inputs/__init__.py               |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/inputs/json_input.py             |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/inputs/parquet_input.py          |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/outputs/__init__.py              |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/outputs/json_output.py           |     2 |    1 |     1 |    50% |
| application_sdk/testing/hypothesis/strategies/outputs/statestore.py            |     3 |    1 |     2 |    67% |
| application_sdk/testing/hypothesis/strategies/server/__init__.py               |     1 |    1 |     0 |     0% |
| application_sdk/testing/hypothesis/strategies/server/fastapi/__init__.py       |     1 |    1 |     0 |     0% |
| application_sdk/testing/integration/__init__.py                                |     1 |    0 |     1 |   100% |
| application_sdk/testing/integration/_errors.py                                 |     4 |    0 |     4 |   100% |
| application_sdk/testing/integration/assertions.py                              |    55 |   25 |    30 |    55% |
| application_sdk/testing/integration/client.py                                  |    18 |    0 |    18 |   100% |
| application_sdk/testing/integration/comparison.py                              |    12 |    1 |    11 |    92% |
| application_sdk/testing/integration/lazy.py                                    |    10 |    0 |    10 |   100% |
| application_sdk/testing/integration/models.py                                  |     9 |    0 |     9 |   100% |
| application_sdk/testing/integration/runner.py                                  |    24 |    2 |    22 |    92% |
| application_sdk/testing/integration/validation.py                              |     7 |    0 |     7 |   100% |
| application_sdk/testing/parity/__init__.py                                     |     1 |    0 |     1 |   100% |
| application_sdk/testing/parity/__main__.py                                     |     2 |    1 |     1 |    50% |
| application_sdk/testing/parity/comparator.py                                   |     8 |    0 |     8 |   100% |
| application_sdk/testing/parity/models.py                                       |     5 |    1 |     4 |    80% |
| application_sdk/testing/parity/report.py                                       |     4 |    0 |     4 |   100% |
| application_sdk/testing/scale_data_generator/__init__.py                       |     1 |    0 |     1 |   100% |
| application_sdk/testing/scale_data_generator/config_loader.py                  |    11 |    4 |     7 |    64% |
| application_sdk/testing/scale_data_generator/data_generator.py                 |    10 |    3 |     7 |    70% |
| application_sdk/testing/scale_data_generator/driver.py                         |     3 |    3 |     0 |     0% |
| application_sdk/testing/scale_data_generator/output_handler/__init__.py        |     1 |    1 |     0 |     0% |
| application_sdk/testing/scale_data_generator/output_handler/base.py            |     7 |    3 |     4 |    57% |
| application_sdk/testing/scale_data_generator/output_handler/csv_handler.py     |     6 |    6 |     0 |     0% |
| application_sdk/testing/scale_data_generator/output_handler/json_handler.py    |     5 |    5 |     0 |     0% |
| application_sdk/testing/scale_data_generator/output_handler/parquet_handler.py |     6 |    6 |     0 |     0% |
| application_sdk/testing/sdr/__init__.py                                        |     1 |    0 |     1 |   100% |
| application_sdk/testing/sdr/base.py                                            |     5 |    2 |     3 |    60% |
| application_sdk/tools/__init__.py                                              |     1 |    1 |     0 |     0% |
| application_sdk/tools/provision_credentials.py                                 |     2 |    1 |     1 |    50% |
| application_sdk/transformers/__init__.py                                       |     3 |    1 |     2 |    67% |
| application_sdk/transformers/errors.py                                         |     2 |    1 |     1 |    50% |
| application_sdk/transformers/atlas/__init__.py                                 |     6 |    1 |     5 |    83% |
| application_sdk/transformers/atlas/errors.py                                   |     8 |    7 |     1 |    12% |
| application_sdk/transformers/atlas/sql.py                                      |    25 |    4 |    21 |    84% |
| application_sdk/transformers/common/__init__.py                                |     1 |    1 |     0 |     0% |
| application_sdk/transformers/common/last_sync.py                               |     5 |    0 |     5 |   100% |
| application_sdk/transformers/common/utils.py                                   |     6 |    0 |     6 |   100% |
| application_sdk/transformers/query/__init__.py                                 |    11 |    2 |     9 |    82% |
| application_sdk/transformers/query/errors.py                                   |     4 |    3 |     1 |    25% |
| contract-toolkit/examples/bundle/app/generated/crawler/__init__.py             |     1 |    1 |     0 |     0% |
| contract-toolkit/examples/bundle/app/generated/crawler/_input.py               |     2 |    2 |     0 |     0% |
| contract-toolkit/examples/bundle/app/generated/miner/__init__.py               |     1 |    1 |     0 |     0% |
| contract-toolkit/examples/bundle/app/generated/miner/_input.py                 |     2 |    2 |     0 |     0% |
| contract-toolkit/examples/connection-ref/app/generated/__init__.py             |     1 |    1 |     0 |     0% |
| contract-toolkit/examples/connection-ref/app/generated/_input.py               |     2 |    2 |     0 |     0% |
| contract-toolkit/examples/deploy/app/generated/__init__.py                     |     1 |    1 |     0 |     0% |
| contract-toolkit/examples/deploy/app/generated/_input.py                       |     2 |    2 |     0 |     0% |
| contract-toolkit/examples/fanin/app/generated/__init__.py                      |     1 |    1 |     0 |     0% |
| contract-toolkit/examples/fanin/app/generated/_input.py                        |     2 |    2 |     0 |     0% |
| contract-toolkit/examples/full/app/generated/__init__.py                       |     1 |    1 |     0 |     0% |
| contract-toolkit/examples/full/app/generated/_input.py                         |     3 |    3 |     0 |     0% |
| contract-toolkit/examples/minimal/app/generated/__init__.py                    |     1 |    1 |     0 |     0% |
| contract-toolkit/examples/minimal/app/generated/_input.py                      |     2 |    2 |     0 |     0% |
| contract-toolkit/examples/publish-controls/app/generated/__init__.py           |     1 |    1 |     0 |     0% |
| contract-toolkit/examples/publish-controls/app/generated/_input.py             |     2 |    2 |     0 |     0% |
| contract-toolkit/scripts/test-sdk-import.py                                    |     3 |    1 |     2 |    67% |
| examples/application_custom_fastapi.py                                         |    10 |    5 |     5 |    50% |
| examples/application_fastapi.py                                                |    10 |    1 |     9 |    90% |
| examples/application_hello_world.py                                            |     6 |    0 |     6 |   100% |
| examples/application_sql.py                                                    |    11 |    3 |     8 |    73% |
| examples/application_sql_miner.py                                              |     9 |    3 |     6 |    67% |
| examples/application_sql_with_custom_transformer.py                            |    12 |    7 |     5 |    42% |
| examples/run_examples.py                                                       |    13 |   12 |     1 |     8% |
| tests/__init__.py                                                              |     1 |    1 |     0 |     0% |
| tests/conftest.py                                                              |     1 |    0 |     1 |   100% |
| tests/e2e/__init__.py                                                          |     1 |    1 |     0 |     0% |
| tests/e2e/conftest.py                                                          |     4 |    1 |     3 |    75% |
| tests/integration/__init__.py                                                  |     1 |    0 |     1 |   100% |
| tests/integration/conftest.py                                                  |    14 |    2 |    12 |    86% |
| tests/integration/test_app_upload_routing.py                                   |     7 |    1 |     6 |    86% |
| tests/integration/test_cloud_store.py                                          |    15 |   12 |     3 |    20% |
| tests/integration/test_core_execution.py                                       |    29 |   24 |     5 |    17% |
| tests/integration/test_dapr_http.py                                            |    22 |    0 |    22 |   100% |
| tests/integration/test_error_and_retry.py                                      |    19 |   15 |     4 |    21% |
| tests/integration/test_events_serde.py                                         |    15 |    5 |    10 |    67% |
| tests/integration/test_handler_service.py                                      |    60 |   31 |    29 |    48% |
| tests/integration/test_heartbeat.py                                            |    13 |   10 |     3 |    23% |
| tests/integration/test_incremental_pipeline.py                                 |    14 |    3 |    11 |    79% |
| tests/integration/test_lifecycle.py                                            |    21 |   17 |     4 |    19% |
| tests/integration/test_multi_entrypoint.py                                     |    26 |   19 |     7 |    27% |
| tests/integration/test_output_e2e.py                                           |    16 |    0 |    16 |   100% |
| tests/integration/test_sql_app_file_reference.py                               |    19 |    9 |    10 |    53% |
| tests/integration/test_sql_app_prime_auth.py                                   |    16 |   11 |     5 |    31% |
| tests/integration/test_storage_io.py                                           |    19 |    0 |    19 |   100% |
| tests/integration/test_storage_writers.py                                      |     9 |    2 |     7 |    78% |
| tests/integration/test_temporal_docker_auth.py                                 |    21 |    8 |    13 |    62% |
| tests/integration/test_timeout.py                                              |     7 |    5 |     2 |    29% |
| tests/integration/test_workflow_interaction_cookbook.py                        |    44 |   37 |     7 |    16% |
| tests/integration/test_workflow_interaction_relay.py                           |    17 |   11 |     6 |    35% |
| tests/integration/_example/__init__.py                                         |     1 |    0 |     1 |   100% |
| tests/integration/_example/conftest.py                                         |     6 |    0 |     6 |   100% |
| tests/integration/_example/scenarios.py                                        |     1 |    0 |     1 |   100% |
| tests/integration/_example/test_integration.py                                 |     2 |    0 |     2 |   100% |
| tests/integration/storage/__init__.py                                          |     1 |    1 |     0 |     0% |
| tests/integration/storage/conftest.py                                          |     5 |    0 |     5 |   100% |
| tests/integration/storage/test_binding_azure.py                                |     6 |    0 |     6 |   100% |
| tests/integration/storage/test_binding_gcs.py                                  |     6 |    0 |     6 |   100% |
| tests/integration/storage/test_binding_s3.py                                   |     7 |    0 |     7 |   100% |
| tests/unit/__init__.py                                                         |     1 |    1 |     0 |     0% |
| tests/unit/conftest.py                                                         |     6 |    1 |     5 |    83% |
| tests/unit/test_app_config.py                                                  |    82 |   45 |    37 |    45% |
| tests/unit/test_discovery.py                                                   |    75 |   69 |     6 |     8% |
| tests/unit/test_imports.py                                                     |     4 |    0 |     4 |   100% |
| tests/unit/test_main.py                                                        |   144 |   64 |    80 |    56% |
| tests/unit/test_parse_atlan_yaml.py                                            |    29 |   25 |     4 |    14% |
| tests/unit/app/__init__.py                                                     |     1 |    1 |     0 |     0% |
| tests/unit/app/test_base.py                                                    |   271 |  218 |    53 |    20% |
| tests/unit/app/test_cleanup_files.py                                           |    15 |   14 |     1 |     7% |
| tests/unit/app/test_cleanup_storage.py                                         |    29 |   26 |     3 |    10% |
| tests/unit/app/test_client.py                                                  |    19 |    1 |    18 |    95% |
| tests/unit/app/test_context.py                                                 |    86 |   72 |    14 |    16% |
| tests/unit/app/test_entrypoint.py                                              |   119 |   78 |    41 |    34% |
| tests/unit/app/test_on_complete.py                                             |    35 |   32 |     3 |     9% |
| tests/unit/app/test_registry.py                                                |    34 |    4 |    30 |    88% |
| tests/unit/app/test_task.py                                                    |    88 |   53 |    35 |    40% |
| tests/unit/clients/__init__.py                                                 |     1 |    1 |     0 |     0% |
| tests/unit/clients/test_async_sql_client.py                                    |    11 |   10 |     1 |     9% |
| tests/unit/clients/test_azure_auth.py                                          |    33 |    0 |    33 |   100% |
| tests/unit/clients/test_azure_client.py                                        |    19 |    0 |    19 |   100% |
| tests/unit/clients/test_azure_client_contracts.py                              |    52 |   46 |     6 |    12% |
| tests/unit/clients/test_base_client.py                                         |    23 |    1 |    22 |    96% |
| tests/unit/clients/test_clienterror_preservation.py                            |    13 |    8 |     5 |    38% |
| tests/unit/clients/test_redis_client.py                                        |    40 |    0 |    40 |   100% |
| tests/unit/clients/test_redis_client_contracts.py                              |    56 |   36 |    20 |    36% |
| tests/unit/clients/test_sql_client.py                                          |    63 |   26 |    37 |    59% |
| tests/unit/clients/test_sql_typecasters.py                                     |    22 |   16 |     6 |    27% |
| tests/unit/clients/test_ssl_utils.py                                           |    41 |    4 |    37 |    90% |
| tests/unit/common/test_aws_utils.py                                            |    32 |    1 |    31 |    97% |
| tests/unit/common/test_column_extraction.py                                    |    11 |    0 |    11 |   100% |
| tests/unit/common/test_env_warnings.py                                         |    10 |    7 |     3 |    30% |
| tests/unit/common/test_file_converter.py                                       |    29 |    0 |    29 |   100% |
| tests/unit/common/test_file_ops.py                                             |    21 |    0 |    21 |   100% |
| tests/unit/common/test_path.py                                                 |     6 |    0 |     6 |   100% |
| tests/unit/common/test_spillable_dict.py                                       |    28 |   18 |    10 |    36% |
| tests/unit/common/test_sql_filters_injection.py                                |    30 |   29 |     1 |     3% |
| tests/unit/common/test_transforms.py                                           |    34 |   31 |     3 |     9% |
| tests/unit/common/test_utils.py                                                |    82 |   11 |    71 |    87% |
| tests/unit/common/test_utils_file_discovery.py                                 |    13 |    0 |    13 |   100% |
| tests/unit/common/incremental/__init__.py                                      |     1 |    1 |     0 |     0% |
| tests/unit/common/incremental/test_helpers.py                                  |    37 |    1 |    36 |    97% |
| tests/unit/common/incremental/test_incremental_diff.py                         |    24 |   15 |     9 |    38% |
| tests/unit/common/incremental/test_marker.py                                   |    16 |    0 |    16 |   100% |
| tests/unit/common/incremental/test_models.py                                   |    15 |    0 |    15 |   100% |
| tests/unit/common/incremental/test_state_reader.py                             |     7 |    1 |     6 |    86% |
| tests/unit/common/incremental/test_state_writer.py                             |    32 |    2 |    30 |    94% |
| tests/unit/common/incremental/column_extraction/__init__.py                    |     1 |    1 |     0 |     0% |
| tests/unit/common/incremental/column_extraction/test_analysis.py               |    16 |   10 |     6 |    38% |
| tests/unit/common/incremental/column_extraction/test_backfill.py               |    24 |    5 |    19 |    79% |
| tests/unit/common/incremental/state/__init__.py                                |     1 |    1 |     0 |     0% |
| tests/unit/common/incremental/state/test_table_scope.py                        |    36 |   26 |    10 |    28% |
| tests/unit/contracts/__init__.py                                               |     1 |    1 |     0 |     0% |
| tests/unit/contracts/test_base.py                                              |   136 |  133 |     3 |     2% |
| tests/unit/contracts/test_connection_ref.py                                    |    31 |   29 |     2 |     6% |
| tests/unit/contracts/test_git_reference.py                                     |    23 |   22 |     1 |     4% |
| tests/unit/contracts/test_storage_tier_temporal_serde.py                       |     9 |    1 |     8 |    89% |
| tests/unit/contracts/test_types.py                                             |    25 |   24 |     1 |     4% |
| tests/unit/credentials/__init__.py                                             |     1 |    1 |     0 |     0% |
| tests/unit/credentials/test_agent.py                                           |    88 |   59 |    29 |    33% |
| tests/unit/credentials/test_atlan.py                                           |    41 |   31 |    10 |    24% |
| tests/unit/credentials/test_atlan_client.py                                    |    29 |   22 |     7 |    24% |
| tests/unit/credentials/test_mock_store.py                                      |    17 |   15 |     2 |    12% |
| tests/unit/credentials/test_oauth.py                                           |    28 |   16 |    12 |    43% |
| tests/unit/credentials/test_ref.py                                             |    26 |   23 |     3 |    12% |
| tests/unit/credentials/test_registry.py                                        |    20 |   18 |     2 |    10% |
| tests/unit/credentials/test_resolver.py                                        |    21 |    9 |    12 |    57% |
| tests/unit/credentials/test_types.py                                           |    42 |   41 |     1 |     2% |
| tests/unit/credentials/test_utils.py                                           |    18 |    1 |    17 |    94% |
| tests/unit/decorators/__init__.py                                              |     1 |    1 |     0 |     0% |
| tests/unit/decorators/test_mcp_tool.py                                         |    56 |    4 |    52 |    93% |
| tests/unit/dev/__init__.py                                                     |     1 |    1 |     0 |     0% |
| tests/unit/dev/test_dapr.py                                                    |    22 |   17 |     5 |    23% |
| tests/unit/dev/test_embedded.py                                                |     6 |    1 |     5 |    83% |
| tests/unit/errors/__init__.py                                                  |     1 |    1 |     0 |     0% |
| tests/unit/errors/test_app_subclassing.py                                      |     9 |    8 |     1 |    11% |
| tests/unit/errors/test_back_compat.py                                          |   102 |  101 |     1 |     1% |
| tests/unit/errors/test_base.py                                                 |    21 |   20 |     1 |     5% |
| tests/unit/errors/test_categorical.py                                          |     7 |    6 |     1 |    14% |
| tests/unit/errors/test_domain_evidence.py                                      |    12 |   10 |     2 |    17% |
| tests/unit/execution/__init__.py                                               |     1 |    1 |     0 |     0% |
| tests/unit/execution/conftest.py                                               |     4 |    2 |     2 |    50% |
| tests/unit/execution/test_activities.py                                        |   119 |  105 |    14 |    12% |
| tests/unit/execution/test_activities_tracking.py                               |    18 |   12 |     6 |    33% |
| tests/unit/execution/test_auth_token_refresh_event.py                          |    62 |   36 |    26 |    42% |
| tests/unit/execution/test_backend.py                                           |    59 |   49 |    10 |    17% |
| tests/unit/execution/test_converter.py                                         |    15 |   12 |     3 |    20% |
| tests/unit/execution/test_eviction.py                                          |    31 |   27 |     4 |    13% |
| tests/unit/execution/test_heartbeat.py                                         |    32 |   18 |    14 |    44% |
| tests/unit/execution/test_lock_interceptor.py                                  |    33 |   13 |    20 |    61% |
| tests/unit/execution/test_run_in_thread.py                                     |     6 |    1 |     5 |    83% |
| tests/unit/execution/test_sdr.py                                               |    31 |   25 |     6 |    19% |
| tests/unit/execution/test_settings.py                                          |    28 |   23 |     5 |    18% |
| tests/unit/execution/test_temporal_prometheus.py                               |     7 |    0 |     7 |   100% |
| tests/unit/execution/test_worker.py                                            |    83 |   64 |    19 |    23% |
| tests/unit/execution/test_workflows.py                                         |    44 |   37 |     7 |    16% |
| tests/unit/handler/__init__.py                                                 |     1 |    1 |     0 |     0% |
| tests/unit/handler/test_base.py                                                |    18 |   17 |     1 |     6% |
| tests/unit/handler/test_contracts.py                                           |    65 |   46 |    19 |    29% |
| tests/unit/handler/test_service.py                                             |   462 |  319 |   143 |    31% |
| tests/unit/infrastructure/__init__.py                                          |     1 |    1 |     0 |     0% |
| tests/unit/infrastructure/test_bindings.py                                     |    18 |   14 |     4 |    22% |
| tests/unit/infrastructure/test_capacity.py                                     |    20 |   16 |     4 |    20% |
| tests/unit/infrastructure/test_connection_pool_config.py                       |    13 |    1 |    12 |    92% |
| tests/unit/infrastructure/test_credential_state_store.py                       |    19 |   12 |     7 |    37% |
| tests/unit/infrastructure/test_credential_vault.py                             |    36 |   17 |    19 |    53% |
| tests/unit/infrastructure/test_dapr_http.py                                    |    45 |   27 |    18 |    40% |
| tests/unit/infrastructure/test_dapr_wrappers.py                                |    46 |   44 |     2 |     4% |
| tests/unit/infrastructure/test_pubsub.py                                       |    30 |   10 |    20 |    67% |
| tests/unit/infrastructure/test_secrets.py                                      |    36 |    0 |    36 |   100% |
| tests/unit/infrastructure/test_state.py                                        |    20 |    0 |    20 |   100% |
| tests/unit/interceptors/__init__.py                                            |     1 |    1 |     0 |     0% |
| tests/unit/interceptors/test_events.py                                         |    42 |   29 |    13 |    31% |
| tests/unit/interceptors/test_log_interceptor.py                                |    84 |   79 |     5 |     6% |
| tests/unit/interceptors/test_metrics_interceptor.py                            |    43 |   41 |     2 |     5% |
| tests/unit/interceptors/test_output_interceptor.py                             |    35 |    3 |    32 |    91% |
| tests/unit/interceptors/test_trace_interceptor.py                              |    17 |   16 |     1 |     6% |
| tests/unit/observability/__init__.py                                           |     1 |    1 |     0 |     0% |
| tests/unit/observability/test_execution_context.py                             |    11 |    0 |    11 |   100% |
| tests/unit/observability/test_logger_adaptor.py                                |   145 |   62 |    83 |    57% |
| tests/unit/observability/test_metrics.py                                       |    11 |   10 |     1 |     9% |
| tests/unit/observability/test_metrics_adaptor.py                               |    29 |    6 |    23 |    79% |
| tests/unit/observability/test_objectstore_metric_exporter.py                   |    17 |   13 |     4 |    24% |
| tests/unit/observability/test_observability_decorator.py                       |    31 |   27 |     4 |    13% |
| tests/unit/observability/test_prometheus_enrichment.py                         |    13 |    8 |     5 |    38% |
| tests/unit/observability/test_pushgateway.py                                   |    50 |   42 |     8 |    16% |
| tests/unit/observability/test_resource_sampler.py                              |    12 |    7 |     5 |    42% |
| tests/unit/observability/test_segment_client.py                                |    70 |   50 |    20 |    29% |
| tests/unit/observability/test_traces_adaptor.py                                |    13 |    1 |    12 |    92% |
| tests/unit/observability/test_traces_adaptor_contracts.py                      |    27 |   22 |     5 |    19% |
| tests/unit/outputs/__init__.py                                                 |     1 |    1 |     0 |     0% |
| tests/unit/outputs/test_outputs.py                                             |    33 |   24 |     9 |    27% |
| tests/unit/server/__init__.py                                                  |     1 |    1 |     0 |     0% |
| tests/unit/server/test_health.py                                               |    24 |   21 |     3 |    12% |
| tests/unit/server/fastapi/test_fastapi_utils.py                                |    36 |    0 |    36 |   100% |
| tests/unit/server/mcp/__init__.py                                              |     1 |    1 |     0 |     0% |
| tests/unit/server/mcp/test_mcp_server_v3.py                                    |    14 |    9 |     5 |    36% |
| tests/unit/server/middleware/__init__.py                                       |     1 |    1 |     0 |     0% |
| tests/unit/server/middleware/test_log.py                                       |    13 |    9 |     4 |    31% |
| tests/unit/storage/__init__.py                                                 |     1 |    1 |     0 |     0% |
| tests/unit/storage/test_batch.py                                               |    36 |   26 |    10 |    28% |
| tests/unit/storage/test_binding.py                                             |    99 |   73 |    26 |    26% |
| tests/unit/storage/test_cloud.py                                               |    45 |   35 |    10 |    22% |
| tests/unit/storage/test_credential_providers.py                                |    11 |   10 |     1 |     9% |
| tests/unit/storage/test_file_ref_sync.py                                       |    37 |   28 |     9 |    24% |
| tests/unit/storage/test_obstore_config.py                                      |    19 |   15 |     4 |    21% |
| tests/unit/storage/test_ops.py                                                 |    98 |   78 |    20 |    20% |
| tests/unit/storage/test_path_separators.py                                     |    13 |    0 |    13 |   100% |
| tests/unit/storage/test_reference.py                                           |    51 |   31 |    20 |    39% |
| tests/unit/storage/test_rolling.py                                             |    68 |   53 |    15 |    22% |
| tests/unit/storage/test_transfer.py                                            |    44 |   34 |    10 |    23% |
| tests/unit/storage/formats/__init__.py                                         |     1 |    1 |     0 |     0% |
| tests/unit/storage/formats/test_base_io.py                                     |    60 |   53 |     7 |    12% |
| tests/unit/storage/formats/test_reader_isolation.py                            |     8 |    2 |     6 |    75% |
| tests/unit/storage/formats/test_utils.py                                       |     2 |    2 |     0 |     0% |
| tests/unit/storage/formats/test_writer_data_integrity.py                       |    26 |    6 |    20 |    77% |
| tests/unit/storage/formats/readers/__init__.py                                 |     1 |    1 |     0 |     0% |
| tests/unit/storage/formats/readers/test_json_reader.py                         |    38 |   18 |    20 |    53% |
| tests/unit/storage/formats/readers/test_parquet_reader.py                      |    68 |   43 |    25 |    37% |
| tests/unit/storage/formats/writers/__init__.py                                 |     1 |    1 |     0 |     0% |
| tests/unit/storage/formats/writers/test_json_writer.py                         |     7 |    6 |     1 |    14% |
| tests/unit/storage/formats/writers/test_parquet_writer.py                      |    74 |   11 |    63 |    85% |
| tests/unit/templates/__init__.py                                               |     1 |    1 |     0 |     0% |
| tests/unit/templates/conftest.py                                               |     2 |    0 |     2 |   100% |
| tests/unit/templates/test_base_metadata_extractor.py                           |    14 |   12 |     2 |    14% |
| tests/unit/templates/test_extraction_input_ae_payload.py                       |    12 |   11 |     1 |     8% |
| tests/unit/templates/test_extraction_input_filters.py                          |    41 |   25 |    16 |    39% |
| tests/unit/templates/test_incremental_sql_metadata_extractor.py                |    89 |   56 |    33 |    37% |
| tests/unit/templates/test_sql_app.py                                           |   117 |   51 |    66 |    56% |
| tests/unit/templates/test_sql_metadata_extractor.py                            |   131 |   99 |    32 |    24% |
| tests/unit/templates/test_sql_query_extractor.py                               |    15 |   12 |     3 |    20% |
| tests/unit/templates/contracts/test_incremental_sql_marker.py                  |    16 |   15 |     1 |     6% |
| tests/unit/testing/__init__.py                                                 |     1 |    1 |     0 |     0% |
| tests/unit/testing/test_fixtures.py                                            |    16 |   15 |     1 |     6% |
| tests/unit/testing/test_mocks.py                                               |    29 |   28 |     1 |     3% |
| tests/unit/testing/test_parity.py                                              |    35 |   34 |     1 |     3% |
| tests/unit/testing/e2e/__init__.py                                             |     1 |    1 |     0 |     0% |
| tests/unit/testing/e2e/test_base_e2e.py                                        |    27 |   23 |     4 |    15% |
| tests/unit/testing/e2e/test_client.py                                          |     9 |    3 |     6 |    67% |
| tests/unit/testing/e2e/test_harness_payload.py                                 |    19 |   16 |     3 |    16% |
| tests/unit/testing/e2e/test_logs.py                                            |    10 |    8 |     2 |    20% |
| tests/unit/testing/e2e/test_portforward.py                                     |     7 |    1 |     6 |    86% |
| tests/unit/testing/e2e/test_sql_app_e2e.py                                     |    35 |   34 |     1 |     3% |
| tests/unit/testing/e2e/test_substitutions.py                                   |    16 |   13 |     3 |    19% |
| tests/unit/testing/full_dag/__init__.py                                        |     1 |    1 |     0 |     0% |
| tests/unit/testing/full_dag/test_base.py                                       |    22 |    3 |    19 |    86% |
| tests/unit/testing/full_dag/test_client.py                                     |    14 |   10 |     4 |    29% |
| tests/unit/testing/full_dag/test_payload.py                                    |    11 |    3 |     8 |    73% |
| tests/unit/testing/full_dag/test_sql_app.py                                    |    12 |    4 |     8 |    67% |
| tests/unit/testing/integration/__init__.py                                     |     1 |    1 |     0 |     0% |
| tests/unit/testing/integration/test_client.py                                  |    25 |   14 |    11 |    44% |
| tests/unit/testing/integration/test_comparison.py                              |    29 |    0 |    29 |   100% |
| tests/unit/testing/integration/test_lazy_pandas.py                             |     5 |    0 |     5 |   100% |
| tests/unit/testing/sdr/__init__.py                                             |     1 |    1 |     0 |     0% |
| tests/unit/testing/sdr/test_base.py                                            |    13 |   11 |     2 |    15% |
| tests/unit/tools/__init__.py                                                   |     1 |    1 |     0 |     0% |
| tests/unit/tools/test_check_migration.py                                       |    65 |   44 |    21 |    32% |
| tests/unit/tools/test_codemod_roundtrip.py                                     |    32 |   31 |     1 |     3% |
| tests/unit/tools/test_extract_context.py                                       |    50 |   48 |     2 |     4% |
| tests/unit/tools/test_fingerprint.py                                           |    23 |   21 |     2 |     9% |
| tests/unit/tools/test_provision_credentials.py                                 |    11 |    0 |    11 |   100% |
| tests/unit/tools/test_rewrite_imports.py                                       |    41 |   31 |    10 |    24% |
| tests/unit/tools/test_run_codemods.py                                          |    16 |   15 |     1 |     6% |
| tests/unit/tools/test_codemods/__init__.py                                     |     1 |    1 |     0 |     0% |
| tests/unit/tools/test_codemods/conftest.py                                     |     2 |    0 |     2 |   100% |
| tests/unit/tools/test_codemods/test_remove_activities_cls.py                   |    15 |   11 |     4 |    27% |
| tests/unit/tools/test_codemods/test_remove_decorators.py                       |    17 |   16 |     1 |     6% |
| tests/unit/tools/test_codemods/test_rewrite_activity_calls.py                  |    16 |   11 |     5 |    31% |
| tests/unit/tools/test_codemods/test_rewrite_entry_point.py                     |    19 |   16 |     3 |    16% |
| tests/unit/tools/test_codemods/test_rewrite_handlers.py                        |    13 |   12 |     1 |     8% |
| tests/unit/tools/test_codemods/test_rewrite_returns.py                         |    12 |   10 |     2 |    17% |
| tests/unit/tools/test_codemods/test_rewrite_signatures.py                      |    19 |   18 |     1 |     5% |
| tests/unit/transformers/__init__.py                                            |     1 |    1 |     0 |     0% |
| tests/unit/transformers/atlas/__init__.py                                      |     1 |    1 |     0 |     0% |
| tests/unit/transformers/atlas/test_atlas_transformer.py                        |    28 |   15 |    13 |    46% |
| tests/unit/transformers/atlas/test_column.py                                   |    17 |    6 |    11 |    65% |
| tests/unit/transformers/atlas/test_database.py                                 |     8 |    6 |     2 |    25% |
| tests/unit/transformers/atlas/test_function.py                                 |    11 |    5 |     6 |    55% |
| tests/unit/transformers/atlas/test_procedure.py                                |     7 |    6 |     1 |    14% |
| tests/unit/transformers/atlas/test_schema.py                                   |     8 |    6 |     2 |    25% |
| tests/unit/transformers/atlas/test_sql_extra.py                                |    42 |   39 |     3 |     7% |
| tests/unit/transformers/atlas/test_table.py                                    |    15 |    6 |     9 |    60% |
| tests/unit/transformers/common/__init__.py                                     |     1 |    1 |     0 |     0% |
| tests/unit/transformers/common/test_last_sync.py                               |    13 |    6 |     7 |    54% |
| tests/unit/transformers/query/test_sql_transformer.py                          |    20 |    4 |    16 |    80% |
| tests/unit/transformers/query/test_sql_transformer_output_validation.py        |     5 |    2 |     3 |    60% |
| tools/migrate_v3/__init__.py                                                   |     1 |    0 |     1 |   100% |
| tools/migrate_v3/check_migration.py                                            |    11 |    6 |     5 |    45% |
| tools/migrate_v3/contract_mapping.py                                           |     3 |    1 |     2 |    67% |
| tools/migrate_v3/extract_context.py                                            |    21 |   16 |     5 |    24% |
| tools/migrate_v3/fingerprint.py                                                |     3 |    1 |     2 |    67% |
| tools/migrate_v3/import_mapping.py                                             |     2 |    0 |     2 |   100% |
| tools/migrate_v3/rewrite_imports.py                                            |    19 |    8 |    11 |    58% |
| tools/migrate_v3/run_codemods.py                                               |    14 |    5 |     9 |    64% |
| tools/migrate_v3/codemods/__init__.py                                          |    11 |    4 |     7 |    64% |
| tools/migrate_v3/codemods/remove_activities_cls.py                             |    12 |    7 |     5 |    42% |
| tools/migrate_v3/codemods/remove_decorators.py                                 |    11 |    8 |     3 |    27% |
| tools/migrate_v3/codemods/rewrite_activity_calls.py                            |     6 |    1 |     5 |    83% |
| tools/migrate_v3/codemods/rewrite_entry_point.py                               |    10 |    3 |     7 |    70% |
| tools/migrate_v3/codemods/rewrite_handlers.py                                  |     8 |    5 |     3 |    38% |
| tools/migrate_v3/codemods/rewrite_returns.py                                   |     7 |    5 |     2 |    29% |
| tools/migrate_v3/codemods/rewrite_signatures.py                                |     8 |    4 |     4 |    50% |
|--------------------------------------------------------------------------------|-------|------|-------|--------|
| TOTAL                                                                          | 10342 | 5429 |  4913 |  47.5% |
---------------- RESULT: PASSED (minimum: 30.0%, actual: 47.5%) ----------------

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

📦 Trivy Vulnerability Scan Results

Schema Version Created At Artifact Type
2 2026-06-04T17:07:51.911041209Z . repository

Report Summary

Could not generate summary table (data length mismatch: 9 vs 8).

Scan Result Details

requirements.txt
uv.lock

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

📦 Trivy Secret Scan Results

Schema Version Created At Artifact Type
2 2026-06-04T17:08:02.597482389Z . repository

Report Summary

Could not generate summary table (data length mismatch: 9 vs 8).

Scan Result Details

requirements.txt
uv.lock

@atlan-ci
Copy link
Copy Markdown
Collaborator

atlan-ci commented Jun 2, 2026

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
17715 16107 91% 0% 🟢

New Files

No new covered files...

Modified Files

No covered modified files...

updated for commit: 2a0e0e3 by action🐍

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

🛠 Full Test Coverage Report: https://k.atlan.dev/coverage/application-sdk/pr/1965

@cmgrote
Copy link
Copy Markdown
Collaborator

cmgrote commented Jun 3, 2026

/regen-manifest

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

✅ Capability manifest regenerated and pushed. The updated SDK-surface diff is now visible in Files changed.

atlan-ci pushed a commit that referenced this pull request Jun 3, 2026
Triggered by /regen-manifest on PR #1965.
Generated by .claude/skills/capability-manifest.
@atlan-ci
Copy link
Copy Markdown
Collaborator

atlan-ci commented Jun 3, 2026

🧪 Connector Tests — atlan-openapi-app

Status: Passed ✅
Dispatched run: 26967201857

Cross-repo dispatch from this SDK PR. Detailed report unavailable — the dispatched run did not produce a results artifact.

@atlan-ci
Copy link
Copy Markdown
Collaborator

atlan-ci commented Jun 3, 2026

🧪 Connector Tests — atlan-mysql-app

Status: Passed ✅
Dispatched run: 26967201750

Cross-repo dispatch from this SDK PR. Detailed report unavailable — the dispatched run did not produce a results artifact.

@cmgrote
Copy link
Copy Markdown
Collaborator

cmgrote commented Jun 3, 2026

@sdk-review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

Earlier @sdk-review trigger (click to expand)

🔍 SDK Review (mothership) triggered by @cmgrote at 2026-06-03T14:26:57.749Z.

Watch the workflow run live — the review summary will appear as a separate comment when complete (typical: 5–30 min, hard cap 2h).


Completed — status completed, cost $18.542982750000007, duration 27m 0s.

@mothership-ai
Copy link
Copy Markdown
Contributor

mothership-ai Bot commented Jun 3, 2026

SDK Review (mothership): PR #1965 — feat(handler): /workflows/v1/input-contract + default entrypoint resolution

Verdict: NEEDS HUMAN REVIEW

Adds a useful schema-introspection endpoint and a workable default-entrypoint mechanism, but the change quietly converts POST /workflows/v1/start on a multi-EP app from 400 to a silent dispatch of the alphabetically-first entrypoint via auto-mark-first. That is a behavior contract change for any caller (Heracles, custom orchestrators) that relied on the 400 to refuse ambiguous requests, and combined with five overlapping default-resolution rules in __init_subclass__, the dispatch policy needs an explicit product decision rather than a code-side patch.


PR Title Check

  • Aligned — title feat(handler): /workflows/v1/input-contract + default entrypoint resolution matches the file scope (SDK bucket: application_sdk/handler/service.py + application_sdk/app/{base,entrypoint}.py). feat(handler): is the right prefix because the user-visible new surface is the handler endpoint.

Findings

application_sdk/app/base.py

  • Important [STRUCT] L497 — __init_subclass__ is now ~170–190 body lines covering five branches (run-only / eps-only / run+eps / auto-mark-first / prohibit @entrypoint(default=True) with run()); past STRUCT-002 ~75-line guidance and the load-bearing branch points are hard to keep in your head. Path: extract _build_entry_points(cls, implicit_ep, explicit_eps) and keep __init_subclass__ as the dispatcher — straightforward PATCH.
  • Important [ARCH] L497 — five overlapping rules for default resolution with asymmetric internal state (implicit auto-flips to default=True only when explicit eps exist; auto-mark-first iterates dir(cls); explicit-default + run() raises). Builders won't be able to predict which rule fires for their layout. Path: design decision — collapse to "exactly one EP → default" + "multiple EPs → must mark exactly one". Drop auto-mark-first. Discuss before patching.
  • Nit [STRUCT] L1 — file is now 2071 lines and growing on each EP-related change. Path: follow-up — split EP/registration logic out of App. Not blocking this PR.

application_sdk/app/entrypoint.py

  • Nit [QUAL] L280 — resolve_default_entrypoint is imported cross-module by handler/service.py and tests, but the name has no leading underscore AND is not in application_sdk/app/__init__.py __all__. Mixed public/internal signal. Path: pick one — add to __all__ + capability manifest as public, OR rename to _resolve_default_entrypoint and document it as internal helper.

application_sdk/handler/service.py

  • Important [ARCH] L945 — POST /workflows/v1/start on a multi-EP app with no ?entrypoint= previously returned 400 (test renamed: test_multi_ep_missing_entrypoint_returns_400test_multi_ep_no_entrypoint_dispatches_auto_default). It now silently dispatches the alphabetically-first EP. For an app exposing both extract and publish, a caller that omits the parameter today will silently invoke extract (or whichever sorts first), which can be the wrong / destructive action. This is a behavioral contract change for every caller of /start. Path: design decision — either (a) keep 400 unless an explicit @entrypoint(default=True) is present, or (b) ship this with a documented migration note and confirm Heracles + any private callers are aligned. Do not auto-fix; needs human + Heracles ack.
  • Important [QUAL] L1850 — try: AppRegistry.get_instance().get(_workflow_config.app_name) except Exception: raise HTTPException(404, ...) from None swallows every internal failure as 404. A registry init bug, a config error, anything raising on the lookup path will look like "App not registered" to the caller. Path: catch KeyError (or whatever the registry's "missing" sentinel is) specifically; let other exceptions bubble to the framework's 500 handler.
  • Important [QUAL] L945 — default-resolution + 404/400/500 mapping is duplicated between start_workflow and the new get_input_contract. Two paths means two places to keep in sync; already mildly divergent. Path: extract _resolve_app_entrypoint(app_name, entrypoint) -> (app_meta, ep) (or raises an HTTPException) and call from both. PATCH-scope.
  • Nit [QUAL] L1855 — HTTPException(status_code=404, detail="App not registered") doesn't include the requested app name. Minor operational ergonomics. Path: include the requested name in the detail string.
  • Nit [STRUCT] L1 — file is now 2119 lines. Same observation as base.py. Path: follow-up — split workflow endpoints from the rest. Not blocking.

docs/concepts/entry-points.md

  • Nit [DOCS] L188 — resolution table claims "first alphabetically", but _scan_entrypoints iterates dir(cls) which orders by Python attribute name, not EntryPointMetadata.name. If a builder names the method differently from name=... in the decorator, the doc will mislead. Path: rephrase as "first by Python attribute name" or sort entry_points by ep.name before picking the auto-default.

Holistic Recommendations

  • Symptoms vs causes: MIXED. The new endpoint and the explicit @entrypoint(default=True) field address real causes (callers couldn't introspect schema; multi-EP apps had no way to declare a default). The auto-mark-first-by-dir(cls) branch addresses a symptom — "start_workflow returned 400 and was annoying" — by silently picking one EP, which is the riskiest decision in the PR.
  • Suggested approach if S4 is contested: keep 400 as the explicit "ambiguous request" signal. Make default=True the only way to opt into silent dispatch on multi-EP apps. Builders that want the old single-EP ergonomics get it for free (len==1 already short-circuits); builders that want a default declare it. That collapses the five rules into two and removes the need for the dir(cls) ordering question entirely.
  • Cross-model note: GPT-5.3-codex flagged a potential regression where __init_subclass__ strict-validates run() annotations even in mixed-mode apps (where explicit eps would otherwise satisfy registration). Confidence 0.89, below the 0.90 inclusion threshold and not independently verified — flagging here so the author can sanity-check that pre-existing apps with un-annotated run() and explicit @entrypoints still register.

Strengths

  • _ENTRYPOINT_NAME_RE = ^[a-zA-Z][a-zA-Z0-9_-]*$ is anchored — no ReDoS surface.
  • All resolution happens at class registration (__init_subclass__), not inside run() / @entrypoint, so no Temporal determinism risk.
  • default: bool = False is purely additive on EntryPointMetadata — contract-safe for in-flight workflows.
  • /workflows/v1/input-contract returns model_json_schema() only — no secrets / tenant data leaked.
  • Lazy import of resolve_default_entrypoint inside the handler preserves the existing circular-import workaround.
  • EntryPointContractError raised at class registration when run() coexists with @entrypoint(default=True) — fails fast, not at request time.
  • 8-scenario test matrix on TestMixedEntrypointRegistration covers the run-only / eps-only / mixed / auto-mark-first / conflict / no-config branches.

CI: all passing
Models: Claude Opus 4.6 (review) + GPT-5.3-codex (adversarial)
Cross-model agreement: 8/9 findings confirmed by both (Q7 dropped — GPT DISAGREE on test-fixture-style preference)
Run: view workflow logs + cost

Copy link
Copy Markdown
Contributor

@mothership-ai mothership-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline notes from the SDK review (see summary comment for verdict). Threads here track the load-bearing findings; please address before merge.

Comment thread application_sdk/handler/service.py Outdated
Comment thread application_sdk/app/base.py Outdated
Comment thread application_sdk/handler/service.py Outdated
# ------------------------------------------------------------------

@app.get("/workflows/v1/input-contract")
async def get_input_contract(entrypoint: str | None = None) -> Response:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Important] [QUAL] — default-resolution + 404/400/500 mapping duplicated across start_workflow and get_input_contract

Evidence: start_workflow (around L972) and the new get_input_contract (this hunk, L1827–1896) both:

  1. Look up the app via AppRegistry.get_instance().get(...).
  2. If ?entrypoint= is present, fetch by name; otherwise call resolve_default_entrypoint(entry_points).
  3. Return 404 on missing app, 400 on missing/ambiguous EP, 500 on the registered-but-empty defensive case.

Two paths means two places to keep aligned; they're already mildly divergent (start_workflow includes the _ENTRYPOINT_NAME_RE check inside its body, this endpoint applies it before the registry lookup).

Path Forward: Extract a private helper, e.g.

def _resolve_app_entrypoint(
    app_name: str, entrypoint: str | None
) -> tuple[AppMetadata, EntryPointMetadata]:
    # raises HTTPException(404 / 400 / 500) on the same conditions
    ...

and call it from both endpoints. The lazy-import pattern still works inside the helper. Reduces the surface area for future drift and shrinks both endpoint bodies.

PATCH-scope; safe follow-up if the design-change findings (L972 / base.py L654) are accepted as-is, since the helper would be the right place to encode whichever resolution policy is chosen.

Comment thread application_sdk/app/base.py Outdated
OnkarVO7 pushed a commit that referenced this pull request Jun 4, 2026
Triggered by /regen-manifest on PR #1965.
Generated by .claude/skills/capability-manifest.
@OnkarVO7 OnkarVO7 force-pushed the onkarravgan/bldx-1354 branch from 1396646 to 7314648 Compare June 4, 2026 09:24
@cmgrote
Copy link
Copy Markdown
Collaborator

cmgrote commented Jun 4, 2026

@sdk-review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

🔍 SDK Review (mothership) triggered by @cmgrote at 2026-06-04T10:04:20.427Z.

Watch the workflow run live — the review summary will appear as a separate comment when complete (typical: 5–30 min, hard cap 2h).

OnkarVO7 pushed a commit that referenced this pull request Jun 4, 2026
Triggered by /regen-manifest on PR #1965.
Generated by .claude/skills/capability-manifest.
@OnkarVO7 OnkarVO7 force-pushed the onkarravgan/bldx-1354 branch from 7314648 to 474aed9 Compare June 4, 2026 10:41
OnkarVO7 and others added 4 commits June 4, 2026 19:10
…resolution

Expose each app's input contract as JSON Schema and let apps declare a
default entrypoint so callers can omit ?entrypoint=.

- GET /workflows/v1/input-contract returns the resolved entrypoint's
  AppInputContract.model_json_schema() (contract_cls resolved from
  AppRegistry), mirroring /workflows/v1/start entrypoint resolution.
  Heracles consumes this to validate request inputs and to detect
  credential fields by the CredentialRef/AgentCredentialSpec $ref.
- @entrypoint(default=True) + EntryPointMetadata.default;
  resolve_default_entrypoint() picks the single entrypoint, or the one
  marked default on multi-entrypoint apps. Registration rejects >1 default.
- /start and /input-contract both resolve the default when ?entrypoint=
  is omitted. Additive: only apps that opt into default=True change
  behavior; single-entrypoint and existing multi-entrypoint apps are
  unaffected.

Part of BLDX-1354 (native app workflow APIs, app-contract-driven).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Triggered by /regen-manifest on PR #1965.
Generated by .claude/skills/capability-manifest.
…as permanent default

Restructures __init_subclass__ to collect both the implicit run() entry
point and explicit @entrypoint-decorated methods into a unified registry,
rather than treating the two paths as mutually exclusive.

Rules:
- run()-only: registered as a single implicit entry point (backward compat)
- @entrypoint-only: registered as before; single ep is the default
- mixed run() + @entrypoint(s): run() is always the default — an
  @entrypoint(default=True) alongside run() is an error
- multiple @entrypoints with no explicit default: first alphabetically
  is auto-marked default; multiple explicit defaults is an error

Tests cover all 8 registration scenarios and all handler invocability
paths (every entry-point combination is reachable via POST
/workflows/v1/start with and without ?entrypoint=).
Add a Default entrypoint resolution reference table to
docs/concepts/entry-points.md, update docs/concepts/apps.md to note
run()+@entrypoint coexistence, and add the same rules as a plain-text
table to the application_sdk/app/entrypoint.py module docstring.

Fixes the stale "multi-entry-point apps require ?entrypoint= (400
otherwise)" claim — multi-ep apps now auto-select the first alphabetical
entry point when the param is omitted.
cmgrote added 2 commits June 4, 2026 19:10
…t behavior

test_multi_ep_missing_workflow_type_returns_400 expected 400 when
?entrypoint= was omitted on a multi-EP app. With auto-default now in
place, the first-alphabetical entry point (route-a) is selected and the
request returns 200. Updated to assert the successful dispatch.
…n and dispatch

- Rename resolve_default_entrypoint → _resolve_default_entrypoint (private)
- Sort _scan_entrypoints output by ep.name so auto-default is alphabetical,
  matching docs ("first alphabetically" claim now accurate)
- Extract _collect_implicit_ep, _scan_entrypoints, _build_entry_points,
  _apply_app_registration, _register_tasks out of base.py into a new private
  module application_sdk/app/_ep_registration.py; base.py imports and
  re-exports them — shrinks base.py by ~240 lines
- Slim App.__init_subclass__ from ~170 lines to ~45 by delegating to the
  extracted helpers
- Add _resolve_app_entrypoint() module-level helper in service.py; both
  /workflows/v1/start and /workflows/v1/input-contract now share one
  resolution path — eliminates duplicated logic and fixes the broad
  except Exception → 404 in get_input_contract (only AppNotFoundError maps
  to 404; other failures bubble to 500)
- Include app name in "App not registered" 404 detail
- Add migration note in start_workflow for the multi-EP auto-default
  behavioral change (previously returned 400, now dispatches alphabetical
  first EP)
- Extract _register_workflow_routes() at module level in service.py;
  create_app_handler_service now delegates all workflow/manifest/event/
  config/file/dev routes to it — shrinks the factory by ~700 lines; related
  helpers (_config_objectstore_key, _provision_local_vault, etc.) also moved
  to module level
@OnkarVO7 OnkarVO7 force-pushed the onkarravgan/bldx-1354 branch from 474aed9 to c421fb7 Compare June 4, 2026 13:40
…ime input_type (BLDX-1354)

The /workflows/v1/input-contract endpoint returned ep.input_type — the type the
@entrypoint run() method accepts. For contract-toolkit apps that is a thin
runtime wrapper (e.g. bigquery's CrawlInput/MinerInput, extra="allow", just two
fields) rather than the rich generated AppInputContract (all configured fields +
CredentialRef-typed credential fields) at app/generated/{entrypoint}/_input.py.
Result: validation no-ops, no field/default discovery, and Heracles can't detect
credentials by $ref.

Auto-discover the generated AppInputContract by convention
(app/generated/{entrypoint}/_input.py, or app/generated/_input.py for single-ep
apps) and serve it; fall back to the runtime input_type when no generated
contract is importable, so apps not using the contract-toolkit are unchanged.

Covered by new tests: generated contract preferred when present (and per-entry
fallback for an entrypoint without one), plus a direct fallback unit test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants