Skip to content

docs: add ADR 0009 for static-context cache-first local persistence#64

Open
jonathannorris wants to merge 17 commits intomainfrom
cursor/offline-context-local-storage-4fb5
Open

docs: add ADR 0009 for static-context cache-first local persistence#64
jonathannorris wants to merge 17 commits intomainfrom
cursor/offline-context-local-storage-4fb5

Conversation

@jonathannorris
Copy link
Member

@jonathannorris jonathannorris commented Mar 6, 2026

Summary

  • add ADR 0009 proposing local persistence with cache-first initialization for static-context OFREP providers
  • on startup, providers load cached evaluations immediately so initial flag evaluations never return defaults, then refresh from the network in parallel
  • define cache-hit and cache-miss initialization paths mapped to the OpenFeature provider lifecycle (PROVIDER_READY, PROVIDER_CONFIGURATION_CHANGED)
  • cache key uses hash(targetingKey), no auth token dependency

Motivation

Every major vendor SDK (LaunchDarkly, Statsig, DevCycle, Eppo) uses cache-first initialization by default. Current OFREP static-context providers keep their cache in memory only, losing all state on restart. See vendor mobile SDK caching research for a detailed comparison.

Related

Test plan

  • not applicable; documentation-only change

@cursor
Copy link

cursor bot commented Mar 6, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces an Architectural Decision Record (ADR) proposing a standard approach for web and mobile OFREP providers to enhance offline functionality. It aims to improve user experience by enabling the persistence of feature flag evaluations in local storage, ensuring that applications can operate and maintain consistent feature states even with intermittent network connectivity or after restarts.

Highlights

  • Offline Resilience for OFREP Static-Context Providers: Proposes that web and mobile OFREP providers should persist their last successful bulk evaluation in local storage by default. This enables offline application startup and preserves feature state across restarts, addressing intermittent connectivity issues.
  • Persistence Mechanism Details: Specifies that the persisted entry should include the bulk evaluation payload, ETag, metadata for matching the current provider instance (like OFREP endpoint and evaluation context), and the write time. It also outlines the initialization flow for loading from local storage.
  • Consequences and Considerations: Discusses positive impacts like improved resilience and consistent offline behavior, as well as negative aspects such as increased provider complexity, potential for stale data, and security/privacy concerns with persisted data.
Changelog
  • service/adrs/0009-localStorageForStaticContextProviders.md
    • Added a new Architectural Decision Record (ADR) proposing the default use of local storage for static-context OFREP providers to enable offline evaluation caching.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

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

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 introduces ADR 0009, which proposes persisting static-context evaluations in local storage for web and mobile providers to improve offline capabilities. The ADR is well-structured and covers the main aspects of the proposal. My review includes a few suggestions to enhance the clarity and robustness of the proposed design, specifically regarding the handling of server errors during initialization, clarifying the purpose of the persisted timestamp, and making the initialization flow more explicit and unambiguous.

Note: Security Review has been skipped due to the limited scope of the PR.

@jonathannorris jonathannorris changed the title Offline context local storage docs: refine ADR 0009 for static-context local persistence Mar 7, 2026
@jonathannorris jonathannorris changed the title docs: refine ADR 0009 for static-context local persistence docs: add ADR 0009 for static-context local persistence Mar 7, 2026
@jonathannorris jonathannorris force-pushed the cursor/offline-context-local-storage-4fb5 branch from e64867d to 9ac24a6 Compare March 7, 2026 12:25
Copy link
Member

@lukas-reining lukas-reining left a comment

Choose a reason for hiding this comment

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

Thanks @jonathannorris, left some feedback.
As you, I think this is a very important addition to the OFREP providers.

I have some thoughts regarding the cache key, which could also influence the whole concept due to the static context possibly also not being available as you said in open question no. 2.

@jonathannorris jonathannorris marked this pull request as ready for review March 13, 2026 02:31
@jonathannorris jonathannorris requested a review from a team as a code owner March 13, 2026 02:31
@gemini-code-assist
Copy link
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@jonathannorris jonathannorris force-pushed the cursor/offline-context-local-storage-4fb5 branch from 85eddc7 to 13ee5b3 Compare March 19, 2026 21:06
jonathannorris and others added 15 commits March 19, 2026 17:08
Co-authored-by: Jonathan Norris <jonathannorris@users.noreply.github.com>
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Co-authored-by: Jonathan Norris <jonathannorris@users.noreply.github.com>
Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Clarify ADR 0009 with provider behavior, persistence examples, and implementation guidance for local cached bulk evaluations.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Clarify initialization flow, explain the persisted timestamp, and define temporary server failures as eligible for persisted fallback.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Specify the cacheKeyHash formula and restore explicit open questions for reviewer feedback.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Document an explicit provider option for turning off persisted local storage.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Drop authToken from cache key derivation and replace sha256 with generic hash(), per reviewer feedback.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
…tion

Specify CACHED as the evaluation reason when serving from persisted storage. Remove fallback scope open question since the decision section already addresses it.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Use must not for auth/config error fallback to prevent masking real problems.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Local storage availability is a platform constraint, not a consequence of the proposal.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Specify that flag values are stored in plaintext and accessible to same-origin code or compromised devices.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
The specific storage key and record model are implementation details.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Remove redundant implementation notes that overlap with the decision section. Simplify mermaid diagram initialize call to use context.

Signed-off-by: Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Replace fallback-on-failure with cache-first initialization pattern aligned with vendor SDKs (LaunchDarkly, Statsig, DevCycle, Eppo). Provider loads from persisted cache immediately on startup, refreshes from network in background, and emits PROVIDER_CONFIGURATION_CHANGED when fresh values arrive.

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
@jonathannorris jonathannorris force-pushed the cursor/offline-context-local-storage-4fb5 branch from 13ee5b3 to 5dbb057 Compare March 19, 2026 21:09
@jonathannorris jonathannorris changed the title docs: add ADR 0009 for static-context local persistence docs: add ADR 0009 for static-context cache-first local persistence Mar 19, 2026
Fix PROVIDER_FATAL to PROVIDER_ERROR with fatal error code per spec. Add rationale for READY vs STALE on cache-hit startup. Clarify cache key tradeoff (targetingKey vs full context). Note existing provider implementations will need lifecycle refactors.

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.com>
@jonathannorris
Copy link
Member Author

/gemini review

Copy link
Contributor

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

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 introduces ADR 0009, which proposes a cache-first local persistence strategy for static-context OFREP providers. The ADR is well-structured and detailed, covering the motivation, design, consequences, and implementation considerations. The proposed cache-first initialization aligns with industry best practices and addresses the 'flash-of-defaults' problem effectively. I have a couple of suggestions to improve the clarity and security aspects of the proposal.

On the cache-hit path, if the background refresh fails with 401/403/400, the provider continues serving cached values for the current session but clears the persisted entry. This ensures the next cold start uses the cache-miss path, making auth errors immediately visible.

Signed-off-by: Jonathan Norris <jonathan.norris@dynatrace.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.

OFREP Static-Context Provider Local Persistence

4 participants