Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Comment |
…pec submodule
The Gherkin, the canonical flag set and the control API document are not Java
artifacts. They are language-agnostic definitions of the provider contract that
every language's TCK must agree on byte for byte, and they only lived in this
module because the proof of concept had to start somewhere.
They now live in open-feature/spec as Appendix F, under
specification/assets/provider-tck/, and are copied in from the `spec` git
submodule at generate-resources — the same mechanism tools/flagd-api-testkit
already uses for the flagd test harness. The copies are git-ignored and carry a
do-not-edit note; changes belong in the spec repo and arrive here by bumping the
submodule.
Consumers are unaffected: the artifacts are still packaged into the release JAR,
@SelectClasspathResource("features") still resolves, and nobody needs a submodule
of their own. Verified byte-identical after the round trip.
The in-memory CI job now checks out submodules, since without them there is no
suite to run.
DEPENDS ON open-feature/spec#423. The submodule is pinned to that PR's branch
commit rather than to a commit on the spec repo's main branch. That is reachable,
so CI can fetch it, but it must be re-pinned to main once #423 merges and before
this lands.
Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
…pec submodule
The Gherkin, the canonical flag set and the control API document are not Java
artifacts. They are language-agnostic definitions of the provider contract that
every language's TCK must agree on byte for byte, and they only lived in this
module because the proof of concept had to start somewhere.
They now live in open-feature/spec as Appendix F, under
specification/assets/provider-tck/, and are copied in from the `spec` git
submodule at generate-resources — the same mechanism tools/flagd-api-testkit
already uses for the flagd test harness. The copies are git-ignored and carry a
do-not-edit note; changes belong in the spec repo and arrive here by bumping the
submodule.
Consumers are unaffected: the artifacts are still packaged into the release JAR,
@SelectClasspathResource("features") still resolves, and nobody needs a submodule
of their own. Verified byte-identical after the round trip.
The in-memory CI job now checks out submodules, since without them there is no
suite to run.
DEPENDS ON open-feature/spec#423. The submodule is pinned to that PR's branch
commit rather than to a commit on the spec repo's main branch. That is reachable,
so CI can fetch it, but it must be re-pinned to main once #423 merges and before
this lands.
Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
lifecycle.feature was tagged @events, which is wrong in both directions.
Too strict: a stateless provider such as OFREP emits no events of its own
and cannot declare @events, yet it still initialises against a backend and
still owes the lifecycle contract.
Too lax: FeatureProviderStateManager emits PROVIDER_READY/PROVIDER_ERROR
around initialize for any provider, whether or not it is an EventProvider.
So a provider that does no initialisation of its own reaches READY exactly
as NoOpProvider would, and the readiness scenario passes vacuously.
Adds Capability.LIFECYCLE ("@lifecycle") -- performs an initialisation that
reaches its backend, with an observable outcome -- and re-vendors
lifecycle.feature verbatim from the spec assets, where the feature-level tag
is now @lifecycle (spec dfa16586, PR open-feature/spec#423).
flagd declares LIFECYCLE in both resolver modes: RPC does a round trip and
in-process syncs the whole ruleset during initialisation, so the scenarios
assert something real there.
Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
…odule The feature files, canonical flag set and control-API document are owned by open-feature/spec. Vendoring them here made this repository a second place the definition of conformance could drift, which is precisely what the suite exists to prevent. They are now a pinned submodule at libs/shared/provider-tck/spec and the copies are gone. Adopters are unaffected, and that is the constraint the change had to respect: the rollup asset globs copy the artifacts out of the submodule and into the published package, so installing @openfeature/provider-tck from npm still needs no submodule and no particular repository layout. resolveAssetDir therefore has to satisfy two layouts -- the packaged copy next to the bundle, and the submodule under the library root -- and tries both. The spec calls the feature directory `gherkin`; the package keeps the name the API talks about. Contributors do need the submodule: without it no feature file loads at all. `nx test` and `nx package` depend on a pullSpec target that initialises it, and CI already checks out with `submodules: recursive`. Prettier is pointed at the submodule instead of the old vendored paths so it never rewrites artifacts that are consumed byte for byte by every language's TCK. The .gitattributes normalising those files to LF goes with them; the equivalent lives upstream, where the files now do. Pinned to dfa1658 (open-feature/spec#423). Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
4661068 to
36392a9
Compare
| @@ -0,0 +1,82 @@ | |||
| { | |||
There was a problem hiding this comment.
I wonder if the canonical flags should also be gherkin? They could be a very large "given", I guess.
There was a problem hiding this comment.
i can see the motivition behind it. but i am not sure it will be easier to read or understand or parse. Especially a json is easily transformed into another JSON for eg. CLI's to prefill databases etc. Not so sure about the gherkin for this purpose.
| Scenario: An integer flag resolves as an integer | ||
| # Paired with the float scenario below and with the narrowing scenario in errors.feature. | ||
| # Together they pin down that the two numeric types stay distinct rather than both being | ||
| # funnelled through one numeric representation. | ||
| Given a Integer-flag with key "integer-flag" and a default value "1" | ||
| When the flag was evaluated with details | ||
| Then the resolved details value should be "10" | ||
| And the error-code should be "" | ||
| And no exception should have been thrown | ||
|
|
||
| Scenario: A float flag resolves as a float | ||
| Given a Float-flag with key "float-flag" and a default value "0.1" | ||
| When the flag was evaluated with details | ||
| Then the resolved details value should be "0.5" | ||
| And the error-code should be "" | ||
| And no exception should have been thrown |
There was a problem hiding this comment.
What about integer precision? I think a lot of our SDKs support resolutions above 32 bit (though some like JS are practically capped at 2⁵³... it might be worth testing at least up to 2⁵³ -1
There was a problem hiding this comment.
fully agree, but for now, i would love to focus on the method, rather than the tests. We should agree and finalize the basic process. Afterwards we can add more tests to ensure compatibility
There was a problem hiding this comment.
added more cases on the side
|
I have to say, the Java impl is remarkably small and clean in Java. I think there's a lot of value here. |
|
I really like the idea, and the impl is clean (though TBH the issue and PR description is very wordy and maybe could be compressed and made less verbose) it took me a long time to get through 😅 . I have 2 things I think I'd want to understand additionally:
|
|
I am in total favor for extensibility. This would even help our providers. We could try to define defaults in java, like a default resource path and a default step path, add those to the test, and have a simply way for the beginning. But also I am not sure, if this would be something which we should delay to the next version. For now, there is the idea, but do we need it immediately to ensure conformance. It sounds like a nice to have feature. A good iteration on the tck, i feel like it could bloat the current efforts. wdyt? I measured what the Java classpath actually does here — the defaults idea works, with one catchFour measurements against the real module:
The third is the catch. If the default resource path is just plus one extra glue package on the base suite ( Net cost: two lines in If it does land, I'd word it in Appendix F as an outcome rather than a mechanism — an adopter can add scenarios and steps that run in the same backend phase without redeclaring the canonical set — since it's pure convention in Java and Python, while Go and JS have no runtime scanning and need one registration callback. Worth separating from the above either way: the suite should verify its canonical scenarios actually ran. That is not about extensibility — the same footgun already exists as // edit: flagd specifically is actually not a good reference example, as we are testing the evaluation engine seperately now. with really good tests. not sure if we want to have all of those tests executed during TCK evaluation. I see the benefit and the ease of running. But the more i think about, the TCK might be best to kept seperate as a verifiable unit, with whom nobody can mingle. Still torn, by both sides |
4c88e46 to
2acd860
Compare
…odule The feature files, canonical flag set and control-API document are owned by open-feature/spec. Vendoring them here made this repository a second place the definition of conformance could drift, which is precisely what the suite exists to prevent. They are now a pinned submodule at libs/shared/provider-tck/spec and the copies are gone. Adopters are unaffected, and that is the constraint the change had to respect: the rollup asset globs copy the artifacts out of the submodule and into the published package, so installing @openfeature/provider-tck from npm still needs no submodule and no particular repository layout. resolveAssetDir therefore has to satisfy two layouts -- the packaged copy next to the bundle, and the submodule under the library root -- and tries both. The spec calls the feature directory `gherkin`; the package keeps the name the API talks about. Contributors do need the submodule: without it no feature file loads at all. `nx test` and `nx package` depend on a pullSpec target that initialises it, and CI already checks out with `submodules: recursive`. Prettier is pointed at the submodule instead of the old vendored paths so it never rewrites artifacts that are consumed byte for byte by every language's TCK. The .gitattributes normalising those files to LF goes with them; the equivalent lives upstream, where the files now do. Pinned to dfa1658 (open-feature/spec#423). Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
lifecycle.feature was tagged @events, which is wrong in both directions.
Too strict: a stateless provider such as OFREP emits no events of its own
and cannot declare @events, yet it still initialises against a backend and
still owes the lifecycle contract.
Too lax: FeatureProviderStateManager emits PROVIDER_READY/PROVIDER_ERROR
around initialize for any provider, whether or not it is an EventProvider.
So a provider that does no initialisation of its own reaches READY exactly
as NoOpProvider would, and the readiness scenario passes vacuously.
Adds Capability.LIFECYCLE ("@lifecycle") -- performs an initialisation that
reaches its backend, with an observable outcome -- and re-vendors
lifecycle.feature verbatim from the spec assets, where the feature-level tag
is now @lifecycle (spec dfa16586, PR open-feature/spec#423).
flagd declares LIFECYCLE in both resolver modes: RPC does a round trip and
in-process syncs the whole ruleset during initialisation, so the scenarios
assert something real there.
Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
…pec submodule
The Gherkin, the canonical flag set and the control API document are not Java
artifacts. They are language-agnostic definitions of the provider contract that
every language's TCK must agree on byte for byte, and they only lived in this
module because the proof of concept had to start somewhere.
They now live in open-feature/spec as Appendix F, under
specification/assets/provider-tck/, and are copied in from the `spec` git
submodule at generate-resources — the same mechanism tools/flagd-api-testkit
already uses for the flagd test harness. The copies are git-ignored and carry a
do-not-edit note; changes belong in the spec repo and arrive here by bumping the
submodule.
Consumers are unaffected: the artifacts are still packaged into the release JAR,
@SelectClasspathResource("features") still resolves, and nobody needs a submodule
of their own. Verified byte-identical after the round trip.
The in-memory CI job now checks out submodules, since without them there is no
suite to run.
DEPENDS ON open-feature/spec#423. The submodule is pinned to that PR's branch
commit rather than to a commit on the spec repo's main branch. That is reachable,
so CI can fetch it, but it must be re-pinned to main once #423 merges and before
this lands.
The pin is the branch tip rather than the first commit of that PR, so the copied
assets carry the `@numeric-coercion` vocabulary and the reserved-capability
control API this branch already uses. Verified byte-identical against the
artifacts this commit deletes.
Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
A vendor with provider-specific features -- flagd's fractional targeting, a proprietary evaluation mode -- had no way to test them inside this suite. The only option was a second Cucumber runner of their own, which means a second backend lifecycle to start and a second copy of this suite's configuration to keep in step with it. Answers @toddbaert's review request on open-feature/spec#423. The suite now also selects the classpath directory tck-extensions/ and the glue package openfeature.tck.extensions. An adopter writes two files and no annotations: src/test/resources/tck-extensions/fractional.feature src/test/java/openfeature/tck/extensions/FractionalSteps.java Their scenarios are discovered into the same suite and the same Cucumber engine, and therefore the same @BeforeAll -- one backend lifecycle, one BackendControl. The canonical steps are on the glue path too, so an extension scenario can open with `Given a stable provider` and continue with whatever is specific to that provider. The extension directory is deliberately not features/ and not a subdirectory of it. Measured on this module: two classpath roots holding the same directory are scanned additively, but two holding the same directory *and* the same file name are not -- one wins silently and the other file is never read, with test-classes beating the jar. An adopter who put features/errors.feature in their test resources would replace a canonical file with their own and watch the suite report success having run theirs. A distinct name makes that collision unreachable rather than documented. The directory ships inside the jar holding nothing but a README, because a @SelectClasspathResource naming a resource that exists on no classpath root is a hard discovery error rather than an empty selection -- so an adopter who extends nothing must still resolve it. Cucumber ignores files that are not .feature, and tolerates a glue package that does not exist, so the unused extension point costs an adopter nothing. Also adds ProviderTck, which names every value the suite's annotations carry. An annotation value has to be a compile-time constant, so an adopter who writes a @ConfigurationParameter of their own cannot compute one; without the constants they would restate our package name or our object factory as a string literal that nothing keeps in step. Constant concatenation is legal in an annotation value, so ProviderTck.ALL_GLUE + ",com.vendor.steps" is what they write instead. The TCK's own fixture -- tck-extensions/extension-selftest.feature and a step class in openfeature.tck.extensions -- is test-scoped, so it is not in the released jar and cannot reach an adopter's run. It sits exactly where an adopter's would, which is the only way to check the convention rather than assert it about a path no build uses. Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
25d000d to
4bab919
Compare
4948f9b to
ff68adb
Compare
…odule The feature files, canonical flag set and control-API document are owned by open-feature/spec. Vendoring them here made this repository a second place the definition of conformance could drift, which is precisely what the suite exists to prevent. They are now a pinned submodule at libs/shared/provider-tck/spec and the copies are gone. Adopters are unaffected, and that is the constraint the change had to respect: the rollup asset globs copy the artifacts out of the submodule and into the published package, so installing @openfeature/provider-tck from npm still needs no submodule and no particular repository layout. resolveAssetDir therefore has to satisfy two layouts -- the packaged copy next to the bundle, and the submodule under the library root -- and tries both. The spec calls the feature directory `gherkin`; the package keeps the name the API talks about. Contributors do need the submodule: without it no feature file loads at all. `nx test` and `nx package` depend on a pullSpec target that initialises it, and CI already checks out with `submodules: recursive`. Prettier is pointed at the submodule instead of the old vendored paths so it never rewrites artifacts that are consumed byte for byte by every language's TCK. The .gitattributes normalising those files to LF goes with them; the equivalent lives upstream, where the files now do. Pinned to dfa1658 (open-feature/spec#423). Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
lifecycle.feature was tagged @events, which is wrong in both directions.
Too strict: a stateless provider such as OFREP emits no events of its own
and cannot declare @events, yet it still initialises against a backend and
still owes the lifecycle contract.
Too lax: FeatureProviderStateManager emits PROVIDER_READY/PROVIDER_ERROR
around initialize for any provider, whether or not it is an EventProvider.
So a provider that does no initialisation of its own reaches READY exactly
as NoOpProvider would, and the readiness scenario passes vacuously.
Adds Capability.LIFECYCLE ("@lifecycle") -- performs an initialisation that
reaches its backend, with an observable outcome -- and re-vendors
lifecycle.feature verbatim from the spec assets, where the feature-level tag
is now @lifecycle (spec dfa16586, PR open-feature/spec#423).
flagd declares LIFECYCLE in both resolver modes: RPC does a round trip and
in-process syncs the whole ruleset during initialisation, so the scenarios
assert something real there.
Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
…pec submodule
The Gherkin, the canonical flag set and the control API document are not Java
artifacts. They are language-agnostic definitions of the provider contract that
every language's TCK must agree on byte for byte, and they only lived in this
module because the proof of concept had to start somewhere.
They now live in open-feature/spec as Appendix F, under
specification/assets/provider-tck/, and are copied in from the `spec` git
submodule at generate-resources — the same mechanism tools/flagd-api-testkit
already uses for the flagd test harness. The copies are git-ignored and carry a
do-not-edit note; changes belong in the spec repo and arrive here by bumping the
submodule.
Consumers are unaffected: the artifacts are still packaged into the release JAR,
@SelectClasspathResource("features") still resolves, and nobody needs a submodule
of their own. Verified byte-identical after the round trip.
The in-memory CI job now checks out submodules, since without them there is no
suite to run.
DEPENDS ON open-feature/spec#423. The submodule is pinned to that PR's branch
commit rather than to a commit on the spec repo's main branch. That is reachable,
so CI can fetch it, but it must be re-pinned to main once #423 merges and before
this lands.
The pin is the branch tip rather than the first commit of that PR, so the copied
assets carry the `@numeric-coercion` vocabulary and the reserved-capability
control API this branch already uses. Verified byte-identical against the
artifacts this commit deletes.
Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
A vendor with provider-specific features -- flagd's fractional targeting, a proprietary evaluation mode -- had no way to test them inside this suite. The only option was a second Cucumber runner of their own, which means a second backend lifecycle to start and a second copy of this suite's configuration to keep in step with it. Answers @toddbaert's review request on open-feature/spec#423. The suite now also selects the classpath directory tck-extensions/ and the glue package openfeature.tck.extensions. An adopter writes two files and no annotations: src/test/resources/tck-extensions/fractional.feature src/test/java/openfeature/tck/extensions/FractionalSteps.java Their scenarios are discovered into the same suite and the same Cucumber engine, and therefore the same @BeforeAll -- one backend lifecycle, one BackendControl. The canonical steps are on the glue path too, so an extension scenario can open with `Given a stable provider` and continue with whatever is specific to that provider. The extension directory is deliberately not features/ and not a subdirectory of it. Measured on this module: two classpath roots holding the same directory are scanned additively, but two holding the same directory *and* the same file name are not -- one wins silently and the other file is never read, with test-classes beating the jar. An adopter who put features/errors.feature in their test resources would replace a canonical file with their own and watch the suite report success having run theirs. A distinct name makes that collision unreachable rather than documented. The directory ships inside the jar holding nothing but a README, because a @SelectClasspathResource naming a resource that exists on no classpath root is a hard discovery error rather than an empty selection -- so an adopter who extends nothing must still resolve it. Cucumber ignores files that are not .feature, and tolerates a glue package that does not exist, so the unused extension point costs an adopter nothing. Also adds ProviderTck, which names every value the suite's annotations carry. An annotation value has to be a compile-time constant, so an adopter who writes a @ConfigurationParameter of their own cannot compute one; without the constants they would restate our package name or our object factory as a string literal that nothing keeps in step. Constant concatenation is legal in an annotation value, so ProviderTck.ALL_GLUE + ",com.vendor.steps" is what they write instead. The TCK's own fixture -- tck-extensions/extension-selftest.feature and a step class in openfeature.tck.extensions -- is test-scoped, so it is not in the released jar and cannot reach an adopter's run. It sits exactly where an adopter's would, which is the only way to check the convention rather than assert it about a path no build uses. Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
The feature files, the flag set they assume and the control API a backend under test must expose, plus a nested Go module so a Go suite can depend on a revision of them the way it depends on any other module. These are the artifacts four conformance implementations execute. Their normative description, Appendix F, follows in its own pull request: it is prose and will take longer to review, while four languages are currently pinned to an unmerged branch, so every rebase here invalidates them. The README carries the capability vocabulary and the skipped-never-passed rule in the meantime, so the tags the feature files use are not left undefined. Experimental: the scenario set is a representative subset and the vocabulary may still change. Tracked in #417. Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
…se-please Two packages. The specification keeps its bare vX.Y.Z tags and excludes the assets path, so an asset-only change does not cut a spec release. The assets are a Go component, tagged specification/assets/provider-tck/vX.Y.Z, which is the shape go get needs -- without it a Go consumer can only name a pseudo-version. Replaces #431, which configured the specification package alone. Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
ff68adb to
8374621
Compare
The spec PR was split: the assets are open-feature/spec#423 and the appendix is #439. This pin follows the assets, so appendix review no longer moves it. The embedded artifacts are byte-identical across the move -- only the assets README changed -- so no tally moves. Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
The spec PR was split: the assets are open-feature/spec#423 and the appendix is #439. This pin follows the assets, so appendix review no longer moves it. The assets consumed here are byte-identical across the move. Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
The spec PR was split: the assets are open-feature/spec#423 and the appendix is #439. This pin follows the assets, so appendix review no longer moves it. PINNED_DIGEST is unchanged, and that is the point: the digest covers flags/, gherkin/ and openapi/, all byte-identical across the move. Only the assets README differs, and it is not an artifact. Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
The spec PR was split: the assets are open-feature/spec#423 and the appendix is #439. This pin follows the assets, so appendix review no longer moves it. The embedded artifacts are byte-identical across the move, so the digest verified at suite start is unchanged and no tally moves. Signed-off-by: Simon Schrottner <simon.schrottner@flagsmith.com>
What
The artifacts a provider conformance suite runs against:
assets/provider-tck/gherkin/assets/provider-tck/flags/canonical-flags.jsonassets/provider-tck/openapi/control-api.yamlassets/provider-tck/go.mod,embed.goembed.FSrelease-please-config.jsonand the workflowMarked experimental: the scenario set is a representative subset, and the capability vocabulary may still change.
Why this is split out
Four language implementations already run these files, and all four are currently pinned to an unmerged branch tip. Every rebase here invalidates them — it has happened three times in two weeks. Nothing about those pins becomes real until the assets are on
mainwith a tag, so landing the executable half first is worth more than landing it together with prose that will take longer to review.Appendix F is the same work, reviewed on its own terms.
Why a Go module is in here
A Go module is distributed as a zip of the VCS tree, in which a git submodule is only a gitlink and its files are absent. The other three languages build from a working tree and keep using the submodule, but a Go suite would have to vendor a copy of every artifact and police it against drift.
embed.goremoves the copy: a consumer pins a revision, the checksum database makes it immutable, and the embedded bytes are the same bytes every other language reads out of the submodule.go.modandembed.goare inert for every non-Go consumer. Precedent:open-feature/flagd-schemas.The release config tags the assets as their own component,
specification/assets/provider-tck/vX.Y.Z— the shapego getneeds. Without it a Go consumer can only name a pseudo-version.Release configuration, and #431
Two packages. The specification keeps bare
vX.Y.Ztags and excludes the assets path, so an asset-only change does not cut a spec release. The assets are a Go component withtag-separator: "/".This replaced #431, which configured the specification package alone and is now closed. Everything in it is here, including both fixes from its review (
issues: write, andtarget-branchrather than thecommand/default-branchinputs v5 ignores).The capability vocabulary lives in the README, for now
A scenario exercising an optional part of the contract carries a tag; a provider declares what it supports, and a scenario gated on an undeclared tag is reported skipped, with the reason — never as passed. A suite that quietly goes green on scenarios it did not run is worse than no suite at all.
That rule and the tag table are in
assets/provider-tck/README.mdso the tags in the feature files are not left undefined while the appendix is in review. #439 moves them into the appendix and leaves a pointer behind, so they end up with one home rather than two that can disagree.Worth stating plainly: withholding a tag is not an admission of a defect.
@numeric-coercionborrows its rule from flagd's coercion ADR, and@string-typing/@fully-typed-valuessit on a question the specification does not answer at all — #430 and #433.Decisions worth reviewing
assets/provider-tck/rather than beside the SDK Gherkin, becauseassets/gherkin/evaluation.featurealready exists and tests an SDK, not a provider. This answers [Tracking] A cross-language conformance suite for OpenFeature providers #417's Q1 — the subdirectory is forced rather than chosen..gitattributesnormalises these to LF. Four languages consume them byte for byte and copy them verbatim into published artifacts, so a Windows checkout must not package differently from a Linux one.missing-flagmust not exist in the flag set — its absence is what theFLAG_NOT_FOUNDscenario tests. The other four load-bearing properties of the flag set are in the README; each one, if seeded wrong, turns a scenario green or red for the wrong reason in every language at once.Implementations
All four execute exactly these files, against flagd (both resolvers), OFREP and Flagsmith:
What running them has found
MultiProviderswallows child provider events — java-sdk#1882