Skip to content

feat(handler): per-entrypoint compute_manifest hook for dynamic apps#1629

Draft
OnkarVO7 wants to merge 6 commits into
mainfrom
feat/dynamic-manifest-compute-hook
Draft

feat(handler): per-entrypoint compute_manifest hook for dynamic apps#1629
OnkarVO7 wants to merge 6 commits into
mainfrom
feat/dynamic-manifest-compute-hook

Conversation

@OnkarVO7
Copy link
Copy Markdown
Collaborator

Summary

Add a convention-based extension point so multi-entrypoint apps can inject dynamic per-submission logic (placeholder fill-in, SQL gen, full DAG rewrite) into the `/manifest` response without monkey-patching `create_app_handler_service` or shipping their own router.

How

The `/manifest` and `/workflows/v1/manifest` handlers now:

  1. Load the static manifest (existing)
  2. Substitute `{deployment_name}` and `{app_name}` (existing)
  3. NEW: look for `app.<entrypoint_snake>.core.compute_manifest` where `entrypoint_snake = entrypoint.replace("-", "_")`. If found and callable, hand it the static manifest dict + the decoded `fe_inputs` query payload (Heracles forwards FE form data this way per atlanhq/heracles#5704). The callable's return dict becomes the response body.

Apps that don't define the convention module get the static manifest unchanged — fully backward-compatible.

Convention rationale

  • Kebab-cased entrypoint names match `atlan.yaml`'s `entrypoints[].name` (and the build pipeline's `parse_atlan_yaml.py` regex)
  • Python module identifiers can't contain hyphens → snake translation
  • The `app.` prefix matches the established `app//` layout used by teradata-app and the new csa-uber-app

API surface

# Apps drop this in: app/<snake>/core.py
def compute_manifest(manifest: dict, fe_inputs: dict) -> dict:
    # transform manifest using submission-time form data
    return {**manifest, \"extras\": fe_inputs}
GET /workflows/v1/manifest?entrypoint=csa-hello-a&fe_inputs=%7B%22x%22%3A1%7D

`fe_inputs` is JSON sent as a URL-encoded query param (no body — keeps the route GET). Empty/missing → hook receives `{}`. Malformed JSON → HTTP 400 (not 500).

Failure-mode matrix

Hook present? `fe_inputs` valid? Result
No n/a Static manifest, unchanged behavior (today's path)
Yes empty/missing Hook called with `{}`, return value used
Yes valid JSON Hook called with decoded dict, return value used
Yes malformed JSON HTTP 400 "fe_inputs is not valid JSON"
Module ImportError (transitive) n/a Hook treated as absent (best-effort), static manifest

Tests

Added `TestComputeManifestHook` with six cases:

  • Hook invocation: callable runs and its return becomes body
  • No-hook fallback: static manifest unchanged
  • Missing `fe_inputs`: hook receives `{}`
  • Malformed `fe_inputs`: HTTP 400
  • Legacy `/manifest` alias forwards `fe_inputs`
  • Kebab → snake module name translation

Tests inject the fake module via `monkeypatch.setitem(sys.modules, ...)` so they don't touch the real filesystem.

Local: 221/221 handler tests pass (was 215; +6 new).

Test plan

  • Local: pre-commit clean (ruff, ruff-format, pyright, isort)
  • Local: `uv run pytest tests/unit/handler` — 221/221
  • CI green
  • Smoke test against atlanhq/atlan-csa-uber-app#11 once that PR rebases on this change — confirm the cleanup deletes `csa_uber_app/sdk_extensions.py` + `csa_uber_app/routes.py` and the `/manifest` endpoint still does dynamic substitution

Replaces

The CSA Uber App's monkey-patch in `csa_uber_app/sdk_extensions.py` (~75 lines) and `csa_uber_app/routes.py` (~125 lines). Follow-up cleanup tracked in atlanhq/atlan-csa-uber-app#11 (will rebase to drop those files once this ships).

Linear: HYP-878

Add a convention-based extension point so multi-entrypoint apps can
inject *dynamic* per-submission logic (placeholder fill-in, SQL gen,
full DAG rewrite) into the `/manifest` response without monkey-patching
`create_app_handler_service` or shipping their own router.

## How

The `/manifest` and `/workflows/v1/manifest` handlers now:

1. Load the static manifest (existing behaviour)
2. Substitute `{deployment_name}` and `{app_name}` (existing behaviour)
3. **NEW**: Look for `app.<entrypoint_snake>.core.compute_manifest`
   where `entrypoint_snake = entrypoint.replace("-", "_")`. If found
   and callable, hand it the static manifest dict + the decoded
   `fe_inputs` query payload (Heracles forwards FE form data this way
   per the Heracles change in atlanhq/heracles#5704). The callable's
   return dict becomes the response body.

Apps that don't define the convention module get the static manifest
unchanged — fully backward-compatible.

Convention rationale: kebab-cased entrypoint names match
`atlan.yaml`'s `entrypoints[].name` (and the build pipeline regex);
Python module identifiers can't contain hyphens, hence the snake
translation. The `app.` prefix matches the established `app/<pkg>/`
layout used by teradata and the new csa-uber-app
(atlanhq/atlan-csa-uber-app#11).

## API surface

```python
# Apps that need dynamic substitution drop this in:
# app/<snake>/core.py
def compute_manifest(manifest: dict, fe_inputs: dict) -> dict:
    return {**manifest, "extras": fe_inputs}
```

```http
GET /workflows/v1/manifest?entrypoint=csa-hello-a&fe_inputs=%7B%22x%22%3A1%7D
```

`fe_inputs` is JSON sent as a URL-encoded query param (no body — keeps
the route GET). Empty/missing → hook receives `{}`. Malformed JSON →
HTTP 400 (not 500).

## Tests

Added `TestComputeManifestHook` with six cases: hook invocation,
no-hook fallback, missing-fe_inputs default, malformed-fe_inputs 400,
legacy `/manifest` alias forwarding, and kebab→snake translation.
Tests inject the fake compute module via `monkeypatch.setitem(sys.modules,
...)` so they don't touch the real filesystem.

221 / 221 handler tests pass.

## Replaces

The CSA Uber App's monkey-patch in `csa_uber_app/sdk_extensions.py`
and ~150 lines of `csa_uber_app/routes.py`. The follow-up cleanup PR
in atlanhq/atlan-csa-uber-app removes both once this ships.
@snykgituser
Copy link
Copy Markdown

snykgituser commented Apr 30, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Code Security 0 0 0 0 0 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 Apr 30, 2026

📜 Docstring Coverage Report

RESULT: PASSED (minimum: 30.0%, actual: 79.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% |
| application_sdk/__init__.py                                                       |     1 |    0 |     1 |   100% |
| application_sdk/constants.py                                                      |     2 |    0 |     2 |   100% |
| application_sdk/discovery.py                                                      |    11 |    2 |     9 |    82% |
| application_sdk/errors.py                                                         |     4 |    1 |     3 |    75% |
| application_sdk/main.py                                                           |    28 |    6 |    22 |    79% |
| application_sdk/version.py                                                        |     1 |    0 |     1 |   100% |
| application_sdk/app/__init__.py                                                   |     1 |    0 |     1 |   100% |
| application_sdk/app/base.py                                                       |    67 |   11 |    56 |    84% |
| application_sdk/app/client.py                                                     |     1 |    0 |     1 |   100% |
| application_sdk/app/context.py                                                    |    38 |    2 |    36 |    95% |
| application_sdk/app/entrypoint.py                                                 |    11 |    3 |     8 |    73% |
| application_sdk/app/registry.py                                                   |    35 |    9 |    26 |    74% |
| application_sdk/app/task.py                                                       |    12 |    5 |     7 |    58% |
| 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/sql.py                                                    |    23 |    1 |    22 |    96% |
| 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/client.py                                           |    13 |    0 |    13 |   100% |
| application_sdk/common/__init__.py                                                |     1 |    0 |     1 |   100% |
| application_sdk/common/aws_utils.py                                               |    10 |    1 |     9 |    90% |
| application_sdk/common/concurrency.py                                             |     3 |    0 |     3 |   100% |
| application_sdk/common/error_codes.py                                             |    14 |    2 |    12 |    86% |
| application_sdk/common/exc_utils.py                                               |     2 |    0 |     2 |   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/sql_filters.py                                             |     9 |    0 |     9 |   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/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                                                 |    36 |    6 |    30 |    83% |
| 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/credentials/__init__.py                                           |     1 |    0 |     1 |   100% |
| application_sdk/credentials/agent.py                                              |     5 |    0 |     5 |   100% |
| application_sdk/credentials/atlan.py                                              |    12 |    6 |     6 |    50% |
| application_sdk/credentials/atlan_client.py                                       |     4 |    0 |     4 |   100% |
| application_sdk/credentials/errors.py                                             |     9 |    4 |     5 |    56% |
| application_sdk/credentials/git.py                                                |     9 |    6 |     3 |    33% |
| application_sdk/credentials/oauth.py                                              |     9 |    1 |     8 |    89% |
| 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/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                                                |     6 |    0 |     6 |   100% |
| application_sdk/execution/sandbox.py                                              |     4 |    0 |     4 |   100% |
| application_sdk/execution/settings.py                                             |     6 |    1 |     5 |    83% |
| application_sdk/execution/_temporal/__init__.py                                   |     1 |    1 |     0 |     0% |
| application_sdk/execution/_temporal/activities.py                                 |     7 |    0 |     7 |   100% |
| application_sdk/execution/_temporal/activity_utils.py                             |     5 |    0 |     5 |   100% |
| application_sdk/execution/_temporal/auth.py                                       |    12 |    0 |    12 |   100% |
| application_sdk/execution/_temporal/backend.py                                    |    10 |    1 |     9 |    90% |
| application_sdk/execution/_temporal/converter.py                                  |     3 |    0 |     3 |   100% |
| application_sdk/execution/_temporal/lock_activities.py                            |     3 |    0 |     3 |   100% |
| application_sdk/execution/_temporal/worker.py                                     |     8 |    3 |     5 |    62% |
| 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/activity_failure_logging.py      |     9 |    0 |     9 |   100% |
| application_sdk/execution/_temporal/interceptors/correlation_interceptor.py       |    15 |   10 |     5 |    33% |
| application_sdk/execution/_temporal/interceptors/events.py                        |    13 |    0 |    13 |   100% |
| application_sdk/execution/_temporal/interceptors/execution_context_interceptor.py |     8 |    4 |     4 |    50% |
| application_sdk/execution/_temporal/interceptors/lock.py                          |    10 |    2 |     8 |    80% |
| application_sdk/execution/_temporal/interceptors/outputs.py                       |     9 |    0 |     9 |   100% |
| application_sdk/handler/__init__.py                                               |     1 |    0 |     1 |   100% |
| application_sdk/handler/base.py                                                   |    13 |    2 |    11 |    85% |
| application_sdk/handler/context.py                                                |    15 |    5 |    10 |    67% |
| application_sdk/handler/contracts.py                                              |    22 |    0 |    22 |   100% |
| application_sdk/handler/manifest.py                                               |     5 |    0 |     5 |   100% |
| application_sdk/handler/service.py                                                |    46 |   22 |    24 |    52% |
| 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                                         |    19 |    4 |    15 |    79% |
| application_sdk/infrastructure/state.py                                           |    10 |    7 |     3 |    30% |
| application_sdk/infrastructure/_dapr/__init__.py                                  |     1 |    0 |     1 |   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/app_vitals.py                                       |    26 |    9 |    17 |    65% |
| application_sdk/observability/context.py                                          |     4 |    0 |     4 |   100% |
| application_sdk/observability/correlation.py                                      |     6 |    0 |     6 |   100% |
| application_sdk/observability/error_classifier.py                                 |     3 |    0 |     3 |   100% |
| application_sdk/observability/logger_adaptor.py                                   |    43 |    8 |    35 |    81% |
| application_sdk/observability/metrics_adaptor.py                                  |    12 |    1 |    11 |    92% |
| application_sdk/observability/models.py                                           |     6 |    0 |     6 |   100% |
| application_sdk/observability/observability.py                                    |    23 |    3 |    20 |    87% |
| application_sdk/observability/resource_sampler.py                                 |     5 |    0 |     5 |   100% |
| application_sdk/observability/segment_client.py                                   |    14 |    2 |    12 |    86% |
| 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                                            |     5 |    1 |     4 |    80% |
| 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/server/middleware/metrics.py                                      |     3 |    2 |     1 |    33% |
| application_sdk/storage/__init__.py                                               |     1 |    0 |     1 |   100% |
| application_sdk/storage/_concurrency.py                                           |     3 |    1 |     2 |    67% |
| application_sdk/storage/_obstore_config.py                                        |     5 |    0 |     5 |   100% |
| application_sdk/storage/batch.py                                                  |     8 |    2 |     6 |    75% |
| application_sdk/storage/binding.py                                                |     4 |    0 |     4 |   100% |
| application_sdk/storage/cloud.py                                                  |    22 |    5 |    17 |    77% |
| application_sdk/storage/errors.py                                                 |     8 |    3 |     5 |    62% |
| 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                                                    |    20 |    1 |    19 |    95% |
| application_sdk/storage/reference.py                                              |    11 |    1 |    10 |    91% |
| application_sdk/storage/transfer.py                                               |    13 |    3 |    10 |    77% |
| application_sdk/storage/formats/__init__.py                                       |    26 |    0 |    26 |   100% |
| application_sdk/storage/formats/json.py                                           |    15 |    1 |    14 |    93% |
| application_sdk/storage/formats/parquet.py                                        |    25 |    1 |    24 |    96% |
| application_sdk/storage/formats/utils.py                                          |     9 |    2 |     7 |    78% |
| application_sdk/templates/__init__.py                                             |     2 |    1 |     1 |    50% |
| application_sdk/templates/base_metadata_extractor.py                              |     3 |    0 |     3 |   100% |
| application_sdk/templates/incremental_sql_metadata_extractor.py                   |    17 |    0 |    17 |   100% |
| application_sdk/templates/sql_metadata_extractor.py                               |    13 |    0 |    13 |   100% |
| application_sdk/templates/sql_query_extractor.py                                  |     5 |    0 |     5 |   100% |
| 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                            |    20 |    0 |    20 |   100% |
| application_sdk/templates/contracts/sql_metadata.py                               |    26 |    4 |    22 |    85% |
| 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/config.py                                             |     2 |    0 |     2 |   100% |
| application_sdk/testing/e2e/logs.py                                               |     6 |    1 |     5 |    83% |
| application_sdk/testing/e2e/pods.py                                               |     5 |    1 |     4 |    80% |
| application_sdk/testing/e2e/portforward.py                                        |     4 |    0 |     4 |   100% |
| application_sdk/testing/e2e/workflows.py                                          |     3 |    0 |     3 |   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/assertions.py                                 |    55 |   25 |    30 |    55% |
| application_sdk/testing/integration/client.py                                     |    16 |    0 |    16 |   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                                 |     6 |    0 |     6 |   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                     |    10 |    4 |     6 |    60% |
| 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/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/atlas/__init__.py                                    |     6 |    1 |     5 |    83% |
| application_sdk/transformers/atlas/sql.py                                         |    25 |    4 |    21 |    84% |
| application_sdk/transformers/common/__init__.py                                   |     1 |    1 |     0 |     0% |
| application_sdk/transformers/common/utils.py                                      |     6 |    0 |     6 |   100% |
| application_sdk/transformers/query/__init__.py                                    |    11 |    2 |     9 |    82% |
| 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_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                                         |    61 |   31 |    30 |    49% |
| 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_storage_io.py                                              |    19 |    0 |    19 |   100% |
| tests/integration/test_timeout.py                                                 |     7 |    5 |     2 |    29% |
| 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/unit/__init__.py                                                            |     1 |    1 |     0 |     0% |
| tests/unit/conftest.py                                                            |     5 |    1 |     4 |    80% |
| tests/unit/test_app_config.py                                                     |    62 |   30 |    32 |    52% |
| tests/unit/test_discovery.py                                                      |    75 |   69 |     6 |     8% |
| tests/unit/test_imports.py                                                        |     4 |    0 |     4 |   100% |
| tests/unit/test_main.py                                                           |   127 |   58 |    69 |    54% |
| tests/unit/test_parse_atlan_yaml.py                                               |    20 |   16 |     4 |    20% |
| tests/unit/app/__init__.py                                                        |     1 |    1 |     0 |     0% |
| tests/unit/app/test_base.py                                                       |   196 |  155 |    41 |    21% |
| 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                                                    |    84 |   70 |    14 |    17% |
| tests/unit/app/test_entrypoint.py                                                 |    65 |   38 |    27 |    42% |
| 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                                                       |    76 |   46 |    30 |    39% |
| 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                                               |    30 |    1 |    29 |    97% |
| tests/unit/common/test_column_extraction.py                                       |    11 |    0 |    11 |   100% |
| 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_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                                                 |   121 |  119 |     2 |     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                                              |    67 |   49 |    18 |    27% |
| tests/unit/credentials/test_atlan.py                                              |    41 |   31 |    10 |    24% |
| tests/unit/credentials/test_atlan_client.py                                       |    14 |    8 |     6 |    43% |
| tests/unit/credentials/test_mock_store.py                                         |    17 |   15 |     2 |    12% |
| tests/unit/credentials/test_oauth.py                                              |    19 |   15 |     4 |    21% |
| 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/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                             |    61 |   35 |    26 |    43% |
| tests/unit/execution/test_backend.py                                              |    37 |   31 |     6 |    16% |
| tests/unit/execution/test_converter.py                                            |    15 |   12 |     3 |    20% |
| tests/unit/execution/test_execution_context_interceptor.py                        |    10 |    1 |     9 |    90% |
| 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_settings.py                                             |    30 |   25 |     5 |    17% |
| tests/unit/execution/test_temporal_prometheus.py                                  |     7 |    0 |     7 |   100% |
| tests/unit/execution/test_worker.py                                               |    51 |   40 |    11 |    22% |
| 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                                              |    32 |   29 |     3 |     9% |
| tests/unit/handler/test_service.py                                                |   324 |  200 |   124 |    38% |
| 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_activity_failure_logging.py                          |    28 |    1 |    27 |    96% |
| tests/unit/interceptors/test_app_vitals.py                                        |    97 |   78 |    19 |    20% |
| tests/unit/interceptors/test_correlation_interceptor.py                           |    18 |    9 |     9 |    50% |
| tests/unit/interceptors/test_events.py                                            |    41 |   29 |    12 |    29% |
| tests/unit/interceptors/test_output_interceptor.py                                |    35 |    3 |    32 |    91% |
| tests/unit/observability/__init__.py                                              |     1 |    1 |     0 |     0% |
| tests/unit/observability/test_app_vitals.py                                       |    75 |   71 |     4 |     5% |
| tests/unit/observability/test_execution_context.py                                |    11 |    0 |    11 |   100% |
| tests/unit/observability/test_logger_adaptor.py                                   |   123 |   58 |    65 |    53% |
| tests/unit/observability/test_metrics_adaptor.py                                  |    28 |    1 |    27 |    96% |
| tests/unit/observability/test_observability.py                                    |    67 |   56 |    11 |    16% |
| tests/unit/observability/test_observability_decorator.py                          |    31 |   27 |     4 |    13% |
| tests/unit/observability/test_resource_sampler.py                                 |    12 |    7 |     5 |    42% |
| tests/unit/observability/test_segment_client.py                                   |    54 |   43 |    11 |    20% |
| 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/storage/__init__.py                                                    |     1 |    1 |     0 |     0% |
| tests/unit/storage/test_batch.py                                                  |    35 |   26 |     9 |    26% |
| tests/unit/storage/test_binding.py                                                |    26 |   19 |     7 |    27% |
| tests/unit/storage/test_cloud.py                                                  |    45 |   35 |    10 |    22% |
| 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                                                    |    92 |   72 |    20 |    22% |
| tests/unit/storage/test_path_separators.py                                        |    13 |    0 |    13 |   100% |
| tests/unit/storage/test_reference.py                                              |    50 |   31 |    19 |    38% |
| tests/unit/storage/test_transfer.py                                               |    39 |   32 |     7 |    18% |
| 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                          |    27 |    7 |    20 |    74% |
| tests/unit/storage/formats/readers/__init__.py                                    |     1 |    1 |     0 |     0% |
| tests/unit/storage/formats/readers/test_json_reader.py                            |    37 |   18 |    19 |    51% |
| tests/unit/storage/formats/readers/test_parquet_reader.py                         |    60 |   38 |    22 |    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                         |    64 |   10 |    54 |    84% |
| 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                             |    22 |    8 |    14 |    64% |
| tests/unit/templates/test_incremental_sql_metadata_extractor.py                   |    89 |   56 |    33 |    37% |
| 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/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_logs.py                                               |    10 |    8 |     2 |    20% |
| tests/unit/testing/e2e/test_portforward.py                                        |     7 |    1 |     6 |    86% |
| tests/unit/testing/integration/__init__.py                                        |     1 |    1 |     0 |     0% |
| tests/unit/testing/integration/test_client.py                                     |    10 |    8 |     2 |    20% |
| tests/unit/testing/integration/test_comparison.py                                 |    29 |    0 |    29 |   100% |
| 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                           |    24 |   13 |    11 |    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/query/test_sql_transformer.py                             |    16 |    4 |    12 |    75% |
| 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                                                                             |  8225 | 4153 |  4072 |  49.5% |
---------------- RESULT: PASSED (minimum: 30.0%, actual: 49.5%) ----------------

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 30, 2026

📦 Trivy Vulnerability Scan Results

Schema Version Created At Artifact Type
2 2026-05-05T15:06:02.304582445Z . 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 Apr 30, 2026

📦 Trivy Secret Scan Results

Schema Version Created At Artifact Type
2 2026-05-05T15:06:16.801922843Z . 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 Apr 30, 2026

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
14102 12673 90% 0% 🟢

New Files

No new covered files...

Modified Files

No covered modified files...

updated for commit: 5d73219 by action🐍

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 30, 2026

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

@OnkarVO7 OnkarVO7 marked this pull request as draft April 30, 2026 13:03
…/fetch_metadata

Mirrors the compute_manifest discovery pattern for the three handler
lifecycle endpoints. Multi-entrypoint apps drop a per-package
`app.<entrypoint_snake>.handler` module exposing plain async
`test_auth` / `preflight_check` / `fetch_metadata` functions; the SDK
discovers them via importlib and dispatches based on the `connector`
field that Heracles already sends in the body.

- Add `connector: str = ""` to AuthInput, PreflightInput, MetadataInput.
- Add `_strip_app_prefix(connector, app_name)` and `_discover_handler_fn`
  helpers in handler/service.py.
- Wire dispatch into the three route handlers; fall through to the
  app-level `Handler` instance when no per-entrypoint module is found.
- Tests: 9 new cases covering hit/miss, empty connector, malformed
  prefix, and entrypoint fn raising.

Backward-compatible: single-entrypoint apps continue to use
`Handler.<fn>` exactly as before.
@cmgrote
Copy link
Copy Markdown
Collaborator

cmgrote commented May 5, 2026

@sdk-review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

🔄 SDK Review starting (review) — ~10-15 min. Watch live progress

Copy link
Copy Markdown
Collaborator

@cmgrote cmgrote left a comment

Choose a reason for hiding this comment

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

Few questions:

  • Can we not define typed contracts everywhere? For example I see methods that return but have no defined return type, translation of JSON into arbitrary dictionaries, etc
  • I'm not crazy about carrying Heracles' "connector" terminology when what we're really talking about is an (app-qualified) entrypoint. Any chance we can rename that on our end proactively (leave renaming in Heracles for another day)?

@vaibhavatlan can you look at & comment on the transformations? I'm seeing various snake/kebab translations -- thought we were centralizing those somewhere else?

PreflightInput: both branches added independent fields (connector from
feature branch, metadata from main). Combined both fields.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

📚 Capability manifest drift detected

docs/agents/sdk-capabilities.md is stale relative to the SDK source on this branch.

To resolve, pick one:

  • Comment /regen-manifest on this PR — a bot will regenerate and push the update.
  • Run uv run poe regen-capabilities locally and push the result.
  • Run the /capability-manifest Claude Code skill locally and push.

This check is informational, not blocking. Reviewers should ensure the manifest is
current before approval so the SDK-surface diff is visible in Files changed.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 5, 2026

SDK Review: PR #1629 — feat(handler): per-entrypoint compute_manifest hook for dynamic apps

Verdict: NEEDS FIXES

Adds convention-based dynamic manifest hook (compute_manifest) and per-entrypoint handler dispatch (test_auth/preflight_check/fetch_metadata). Design is sound and backward-compatible. Two Important issues: the compute_manifest hook is documented as sync-only but called directly on the event loop (will block if the hook does I/O), and the _discover_* helpers lack return-type annotations (would fail Pyright strict). Tests are thorough (6 + 11 new cases) and well-isolated.

Findings by File

application_sdk/handler/service.py

  • Important [ARCH] L1677 — compute_manifest hook is called synchronously (manifest_dict = compute(manifest_dict, form)) inside an async def endpoint. If the hook performs any I/O (DB queries, HTTP calls, file reads), it will block the event loop. The per-entrypoint handler functions are properly awaited, but this hook has no async support. Fix: support both sync and async hooks — if asyncio.iscoroutinefunction(compute): manifest_dict = await compute(manifest_dict, form) else: manifest_dict = compute(manifest_dict, form) or document the hook MUST be CPU-only and add a timeout/thread-pool wrapper.
  • Important [QUAL] L269, L329 — _discover_compute_manifest and _discover_handler_fn lack return-type annotations. They return Callable | None — add -> Callable[..., Any] | None (or a Protocol). These are private helpers, but given Pyright strict is enforced per the pre-commit rules, missing annotations will fail CI. Fix: add -> Callable[..., Any] | None return annotations.
  • Minor [STRUCT] L269-371 — service.py is now 1899 lines (was ~1578 per structural rules baseline). The four new helpers (_discover_compute_manifest, _entrypoint_from_connector, _discover_handler_fn, _decode_fe_inputs) add cohesive functionality and are well-scoped, but this file continues to grow. Not a blocker, but a future refactor target (e.g., extract a discovery.py module).

application_sdk/handler/contracts.py

  • No issues. The connector: str = "" field additions follow additive-evolution rules (ADR-0006) — new field with default, backward-compatible.

tests/unit/handler/test_service.py

  • No issues. Tests are isolated, use monkeypatch/tmp_path, cover happy-path + fallback + error cases, and have specific assertions.

Strengths

  • Clean backward-compatible design — apps without the hook are completely unaffected.
  • Longest-suffix matching in _entrypoint_from_connector is a thoughtful approach to the connector-prefix ambiguity problem.
  • Thorough test coverage for both features including edge cases (kebab→snake, no-match connector, malformed JSON).
  • Good use of OSError catch + (ModuleNotFoundError, ImportError) for best-effort discovery that can never crash the handler.

OnkarVO7 and others added 2 commits May 5, 2026 20:34
…or absent

Heracles' configmap-based credential metadata path forwards the config
name (e.g. "atlan-connectors-asset-export-advanced") but doesn't always
populate the body's `connector` field, so the per-entrypoint dispatch
on /workflows/v1/{auth,check,metadata} silently fell through to the
app-level Handler instead of routing to `app.<snake>.handler.<fn>`.

Adds a `_resolve_entrypoint` helper that tries `connector` first and
falls back to `connectorConfigName`; both call into the existing
`_entrypoint_from_connector` which now also accepts an exact-match
(connector == entrypoint) on top of the documented hyphen-suffix.

Also retargets the three "no entrypoint module" fallback tests at a
contrived `sdk-fallback-noep-*` name so they don't collide with real
`app.csa_hello_*` modules that may be on PYTHONPATH in dev envs where
the uber-app repo is editable-installed alongside the SDK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lter

Heracles' app client posts the widget-specific filter key as
``metadataTemplateKey`` (and a ``type`` mirror it adds) but the v3 SDK's
``MetadataInput`` only exposes ``object_filter``. Per-entrypoint hooks
that branch their fetch_metadata response by widget — e.g.
asset-export-advanced returning tags vs connectors vs typenames vs
custommetadata — saw an empty ``object_filter`` and fell through to
their default branch, so every widget rendered the same fallback list.

Bridge the gap in the /workflows/v1/metadata route: when
``object_filter`` is empty after model_validate, populate it from
``metadataTemplateKey`` (preferred) or ``type`` (Heracles mirror) read
from the raw request body. An explicit ``object_filter`` in the body
still wins.

Co-Authored-By: Claude Opus 4.7 (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