Skip to content

feat(schemas): add feature state metadata envelope - #272

Open
Zaimwa9 wants to merge 1 commit into
mainfrom
feat/feature-state-metadata-schema
Open

Zaimwa9 wants to merge 1 commit into
mainfrom
feat/feature-state-metadata-schema

Conversation

@Zaimwa9

@Zaimwa9 Zaimwa9 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Thanks for submitting a PR! Please check the boxes below:

  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Contributes to Flagsmith/edge-api#719

Core is adding an optional metadata dict to feature states.
Its first key is experiment { id, name, started_at, in_experiment }, present only while the feature's experiment is running.
This PR adds the envelope to the schemas so nothing strips it on the way through.

api.py

  • ExperimentMetadata and FeatureStateMetadata TypedDicts.
  • metadata: NotRequired[FeatureStateMetadata] on FeatureState (environment document) and V1Flag (/identities).
  • FeatureStateMetadata keeps unknown keys (PEP 728 extra_items, same pattern as JsonRecord), so future keys land without a schema change.

dynamodb.py

  • FeatureState.metadata: NotRequired[dict[str, Any]], opaque.
  • Without it, Core's compressed-document validation drops the key.

How did you test this code?

9 new tests:

  • round-trip with experiment
  • unknown key inside metadata preserved
  • wrong experiment.id type still rejected
  • gzip DynamoDB round-trip
  • key absent when unset

uv run --all-extras pytest: 406 passed.
pre-commit run --all-files and mypy src tests: green.

@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: d9bbc1fa-e697-470d-9ddf-a77ed52cb53b

📝 Walkthrough

Walkthrough

The API schemas add typed experiment metadata and optional metadata fields to FeatureState and V1Flag. Undeclared metadata keys are preserved. The DynamoDB schema adds optional opaque metadata. Tests cover validation, omission when absent, direct round-tripping, and preservation through compressed environment serialisation.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: 🔵 Low · up to 8d505

Invalid experiment start timestamps can be returned in API metadata. Add UTC-preserving validation before merging.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

codecov-commenter commented Sep 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.64%. Comparing base (314c071) to head (4af9b4e).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #272      +/-   ##
==========================================
+ Coverage   97.61%   97.64%   +0.03%     
==========================================
  Files         109      110       +1     
  Lines        4859     4921      +62     
==========================================
+ Hits         4743     4805      +62     
  Misses        116      116              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 2bb7e9b7-4d90-41be-b59f-b330aa30bc4e

📥 Commits

Reviewing files that changed from the base of the PR and between 314c071 and 8d5056b.

📒 Files selected for processing (4)
  • src/flagsmith_schemas/api.py
  • src/flagsmith_schemas/dynamodb.py
  • tests/integration/flagsmith_schemas/test_api.py
  • tests/integration/flagsmith_schemas/test_dynamodb.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread src/flagsmith_schemas/api.py Outdated
"""Unique identifier for the experiment in Core."""
name: str
"""Name of the experiment."""
started_at: str

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Validate started_at as UTC without changing the wire value.

ExperimentMetadata.started_at is declared as str, so TypeAdapter(FeatureState).validate_python(...) accepts "not-a-timestamp" despite the documented ISO 8601 UTC contract.

DateTimeStr is not a drop-in fix. Its ValidateAs(datetime, lambda dt: dt.isoformat()) validator accepts naive or non-UTC datetimes and normalises "2026-07-30T00:00:00Z" to a +00:00 form. This conflicts with test_feature_state__metadata_experiment__expected_result, which requires the validated payload to equal the input.

Add an API-specific validated string type that requires a UTC timestamp and preserves the original serialised string.

@Zaimwa9
Zaimwa9 force-pushed the feat/feature-state-metadata-schema branch from 8d5056b to 271fe0b Compare September 15, 2026 08:29
@Zaimwa9

Zaimwa9 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

@themis-blindfold review

@themis-blindfold

Copy link
Copy Markdown

⚖️ Themis review: 🧹 Ship it, nits inside

TL;DR: The new envelope is carried through the public SDK and DynamoDB schemas, including compressed environment documents. CI passed for lint-test on Python 3.11 and 3.12, CodeRabbit, and pre-commit; one schema-documentation nit remains open.

Area Score
🎯 Correctness 4/5
🧪 Test coverage 4/5
📐 Code quality 4/5
🚀 Product impact 3/5

🧹 Nits

  • src/flagsmith_schemas/api.py:69started_at accepts non-ISO/non-UTC strings despite its documented contract.
📝 Walkthrough
  • API schemas - expose optional feature-state metadata for flag and environment-document responses.
  • DynamoDB schemas - retain the opaque metadata envelope through normal and gzipped document validation.
  • Tests - cover known experiment fields, forward-compatible keys, omitted metadata, and gzip round-tripping.
🧪 How to verify
  1. Run uv run --all-extras pytest tests/integration/flagsmith_schemas/test_api.py.
  2. Run uv run --all-extras pytest tests/integration/flagsmith_schemas/test_dynamodb.py.
  3. Exercise EnvironmentCompressed and EnvironmentV2MetaCompressed with metadata containing an unknown nested key, then decompress and compare the payload.
  4. Validate an API flag with a malformed or non-UTC metadata.experiment.started_at value once the timestamp contract is enforced.
    Automate: add the malformed/non-UTC timestamp cases with that validation.

Product take: A small but useful compatibility addition: experiment context can now reach SDK consumers without being stripped. Its value is concentrated in experiment-aware clients.

🧭 Assumptions & unverified claims

No unverified assumptions or claims.

Metadata made it through the gzip tunnel intact · reviewed at 271fe0b

@Zaimwa9
Zaimwa9 force-pushed the feat/feature-state-metadata-schema branch from 271fe0b to 2b8e57e Compare September 15, 2026 08:55
@Zaimwa9
Zaimwa9 force-pushed the feat/feature-state-metadata-schema branch from 2b8e57e to 4af9b4e Compare September 15, 2026 08:57
@Zaimwa9
Zaimwa9 marked this pull request as ready for review September 15, 2026 08:58
@Zaimwa9
Zaimwa9 requested a review from a team as a code owner September 15, 2026 08:58
@Zaimwa9
Zaimwa9 requested review from gagantrivedi and matthewelwell and removed request for a team and matthewelwell September 15, 2026 08:58

@gagantrivedi gagantrivedi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we need start date?

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.

3 participants