Skip to content

feat: support sdk key and direct config initialization - #9

Merged
usmanabbas7 merged 1 commit into
dev-branchfrom
feat-story-1.2-support-sdkkey-and-direct-config-initialization
Apr 8, 2026
Merged

feat: support sdk key and direct config initialization#9
usmanabbas7 merged 1 commit into
dev-branchfrom
feat-story-1.2-support-sdkkey-and-direct-config-initialization

Conversation

@usmanabbas7

Copy link
Copy Markdown
Collaborator

Summary

Implements Story 1.2, "Support sdkKey and Direct-Config Initialization," for the Python SDK.

This PR adds the first real SDK initialization behavior on top of the Story 1.1 scaffold. The SDK can now initialize from either:

  • direct config data provided at startup
  • an sdk_key fetched from the Convert config endpoint over HTTPS

It also establishes the immutable config snapshot foundation that later stories will use for context creation and evaluation.

What Changed

  • Added public initialization config types:
    • SDKConfig
    • TransportConfig
  • Added typed initialization/config errors:
    • InitializationError
    • ConfigValidationError
    • ConfigLoadError
  • Extended Core to initialize from either direct config data or sdk_key
  • Added config validation and normalization helpers under convert_sdk.config_loader
  • Added immutable ConfigSnapshot creation with precomputed entity indexes
  • Added a transport port and an httpx-backed sync transport adapter
  • Added README examples for both direct-config and sdk_key initialization
  • Added automated tests for initialization, transport behavior, and error handling
  • Updated packaging expectations to allow the new httpx runtime dependency

Why

The planning artifacts for Story 1.2 call for the SDK to support both preloaded and networked initialization modes while keeping the MVP public API sync-first and framework-agnostic.

This PR establishes:

  • the canonical Python initialization contract
  • authoritative readiness state on Core
  • immutable config ingestion instead of mutable raw dictionaries
  • typed, diagnosable failures for invalid config and fetch failures

That gives later stories a stable base for visitor contexts, evaluation, and tracking.

Validation

Ran in ../python-sdk:

  • uv sync --group dev
  • uv run pytest -p no:cacheprovider
  • uv build

Results:

  • all 10 tests passed
  • wheel and sdist built successfully

Notes

This PR is intentionally limited to initialization and config ingestion.
It does not yet implement:

  • visitor context creation/reuse
  • evaluation behavior
  • tracking or event delivery
  • persistence/state mutation flows

@usmanabbas7
usmanabbas7 merged commit 9fb1516 into dev-branch Apr 8, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request establishes the core initialization framework for the Convert Python SDK, including configuration management, validation, and immutable domain snapshots. It introduces an HTTPX-based transport adapter and a typed error hierarchy. The review feedback suggests enhancing documentation with error-handling examples, using explicit assertions for type safety in the configuration loader, and removing redundant validation calls.

Comment thread README.md
Comment on lines +48 to +57
core = Core(
SDKConfig(
sdk_key="1001/2002",
environment="staging",
transport=TransportConfig(
config_endpoint="https://cdn-4.convertexperiments.com/api/v1",
),
)
)
assert core.is_ready

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The example for initializing with an SDK key is helpful. To make it more robust and production-ready for users, consider demonstrating how to handle potential initialization failures. Since this involves a network request, it could fail and raise an InitializationError. Wrapping the call to Core() in a try...except block would be a great addition.

For example:

from convert_sdk import Core, SDKConfig, TransportConfig, InitializationError

try:
    core = Core(
        SDKConfig(
            sdk_key="1001/2002",
            # ...
        )
    )
    assert core.is_ready
    print("SDK initialized successfully!")
except InitializationError as e:
    print(f"SDK initialization failed: {e}")

Comment on lines +20 to +25
request = ConfigRequest(
sdk_key=config.sdk_key or "",
sdk_key_secret=config.sdk_key_secret,
environment=config.environment,
transport=config.transport,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

While config.sdk_key or "" works to satisfy the type checker, it's less clear than an explicit assertion. Since validate_sdk_config is called just before this, we can be sure that config.sdk_key is not None. Using an assert makes this assumption explicit, which improves readability and helps static analysis tools.

Suggested change
request = ConfigRequest(
sdk_key=config.sdk_key or "",
sdk_key_secret=config.sdk_key_secret,
environment=config.environment,
transport=config.transport,
)
assert config.sdk_key is not None
request = ConfigRequest(
sdk_key=config.sdk_key,
sdk_key_secret=config.sdk_key_secret,
environment=config.environment,
transport=config.transport,
)

Comment on lines +28 to +29
if has_config_data:
validate_config_data(config.config_data)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The load_config_snapshot function already calls validate_config_data when config.config_data is present. This call within validate_sdk_config is redundant and causes the validation to be performed twice. It's best to keep validation concerns separate and let the orchestrator (load_config_snapshot) handle the sequence of validation calls.

@abbaseya
abbaseya deleted the feat-story-1.2-support-sdkkey-and-direct-config-initialization branch June 18, 2026 16:37
abbaseya added a commit that referenced this pull request Aug 8, 2026
All eight open Dependabot alerts on this repo sit in `yarn.lock` — the
dev-only semantic-release tooling. None of them reach the published
wheel/sdist (httpx is still the only runtime dependency).

Three of the four highs were already reachable inside the existing semver
ranges; the fourth (sigstore GHSA-52v5-jr5w-gjxr, `certificateOIDs`
verification constraints silently dropped) needed sigstore >= 4.1.1, which
only arrives through a major bump:

  semantic-release 24.2.9 -> 25.0.9
    @semantic-release/npm 12.0.2 -> 13.1.5
      npm 10.9.8 -> 11.19.0
        libnpmpublish 10 -> 11.2.0  }-> sigstore ^3 -> ^4  (4.1.1)
        pacote        19 -> 21.5.1  }   @sigstore/core 2.0.0 -> 3.2.1
        tar 7.5.16 -> 7.5.22

`@semantic-release/github` moves to ^12 to match what semantic-release 25
depends on — leaving it at ^11 would hoist the older copy to the project
root and shadow the one core resolves.

Resolved (4 high, 4 medium — no criticals were open):

  #14 high    ip-address       10.2.0 -> 10.4.0   (needs >= 10.3.1)
  #9  high    brace-expansion  2.1.1  -> 5.0.9    (needs >= 2.1.2)
  #7  high    js-yaml          4.2.0  -> 4.3.1    (needs >= 4.3.0)
  #2  high    sigstore         3.1.0  -> 4.1.1    (needs >= 4.1.1)
  #13 medium  ip-address       (same bump as #14)
  #12 medium  ip-address       (same bump as #14)
  #4  medium  tar              7.5.16 -> 7.5.22   (needs >= 7.5.18)
  #1  medium  @sigstore/core   2.0.0  -> 3.2.1    (needs >= 3.2.1)

Node: semantic-release 25 requires ^22.14.0 || >= 24.10.0. release.yml
installs `lts/*`, currently Node 24.19.0 — satisfied, and every future LTS
line stays above the floor.

Verified: `yarn install --immutable` (what release.yml runs) passes against
the regenerated lockfile with the lockfile format unchanged (__metadata
version 10), and `yarn npm audit --all --recursive` reports no suggestions.
A `semantic-release --dry-run` against this branch loads all four configured
plugins, passes verifyConditions for both exec and github (GitHub
authentication + push permission), and analyzes commits to "no release" —
correct, since `chore` is a non-releasing type in release.config.mjs.

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

1 participant