quonfig 0.0.19 → 0.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f71f10c80365079815e7b7d7f2a9a8926ecfc358697505bb3c6bd3f2e6142976
4
- data.tar.gz: 3d0988da2eb9a17457dc53c358e32a55aaa17f59e1c7c280db5db52b3eb991fc
3
+ metadata.gz: 417fb2012b91e48124294300c5d480ef08a822a6f5c42efff05e9334336ae884
4
+ data.tar.gz: a5fe1a4548e4d332ada2ce2c01c4d74f604d1273ad8d58338d3ea8653670629c
5
5
  SHA512:
6
- metadata.gz: e019ac9393b2644208aaa79fbbed9bfe0a27e346413ffac2cd126d47fd9ffa114a1af4bfcd597b527577935a586ea6636aa6e8c96be8ee657889bc324d9ea38c
7
- data.tar.gz: 89026759a78f4219766b14366630a5df3a3126884c5bfa721764cffdf6799c8f47df5be1245c86c8966aedbbb9a4508b65d53a400cd3c6e4308f872bc975f6ce
6
+ metadata.gz: aa3cd21079aad1feb9b7ddab61dacb4e9ebb79dcf1562b2283b46b50daa613fe844f9685015bd3f82efd3200817b8ba032899ce0a7a785a3fcfeda994417daf3
7
+ data.tar.gz: 0d848cebe378a700f9accd09cdbe6dcd78071a83a9c56734fa765e094b36acadf5f888d46fbb7dbc81c76e06a0611ac68dc1a2689833aef08f57e2674cfe8c71
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.0.21 - 2026-06-02
4
+
5
+ - **Dev-context injection is now default-on (qfg-bw7g.5).** `enable_quonfig_user_context` now defaults to `nil` (unset). When left unset it defaults to **on**, gated solely by the presence of `~/.quonfig/tokens.json`; the loader no-ops without that file, so this stays inert in production. New `dev_context_enabled?` precedence: explicit `enable_quonfig_user_context` option ?? `QUONFIG_DEV_CONTEXT` env (`true`/`false`) ?? `true`. Pass `enable_quonfig_user_context: false` or set `QUONFIG_DEV_CONTEXT=false` to opt out.
6
+
7
+ ## 0.0.20 - 2026-05-29
8
+
9
+ - **Fix (delivery): derive evaluator env from `meta.environment` in HTTP+SSE delivery mode (qfg-xpln.2).** Per-environment overrides were not being applied when the SDK ran in delivery mode (HTTP fetch + SSE stream). The evaluator now derives its `env_id` from the authoritative `meta.environment` carried on every delivery envelope, so environment-scoped rules and overrides resolve correctly against the environment api-delivery actually served — matching datadir-mode behavior.
10
+ - **Fix (options): an explicit environment pin is datadir-only; ignored in delivery mode with a WARN (qfg-pinh).** In delivery mode the served envelope's `meta.environment` is authoritative — the environment is decided server-side by api-delivery, not by the client. A client-supplied environment pin (`with_environment` / `QUONFIG_ENVIRONMENT`) is therefore only meaningful in datadir mode. In delivery mode the pin is now ignored and a one-time WARN is logged so the conflict is visible rather than silently misleading.
11
+
3
12
  ## 0.0.19 - 2026-05-28
4
13
 
5
14
  - **Deprecation (context): `in_context` is now a deprecated alias of `with_context` (qfg-e0kk).** The two methods have always been runtime-identical — both accept a properties hash and either yield a `Quonfig::BoundClient` to a given block or return the BoundClient directly. As part of the sdk-1.0 unification, every SDK in the family is converging on the `with_context` family; sdk-ruby keeps `in_context` as a YARD-`@deprecated` alias for the 1.0.0 cycle so existing customer code (especially Prefab-fork lineage call sites) keeps working without a runtime warning. Implementation collapses to a one-line forward (`in_context` now calls `with_context`), and the README example is updated to use `with_context`. Slated for removal in 2.0.0.
@@ -714,6 +714,14 @@ module Quonfig
714
714
  old_keys = @store.keys.to_set
715
715
  (old_keys - new_keys).each { |k| @store.delete(k) }
716
716
  envelope.configs.each { |cfg| @store.set(cfg['key'], cfg) }
717
+ # qfg-pinh: evaluate against the installed envelope's meta.environment,
718
+ # matching sdk-go. In datadir mode the loader stamps meta.environment =
719
+ # the resolved env (the `environment:` pin or QUONFIG_ENVIRONMENT), so
720
+ # this also covers the env-var-only case where @options.environment is
721
+ # nil at evaluator construction.
722
+ meta = envelope.respond_to?(:meta) ? envelope.meta : nil
723
+ env_id = meta && (meta['environment'] || meta[:environment])
724
+ @evaluator.env_id = env_id if env_id && !env_id.to_s.empty?
717
725
  record_refresh!
718
726
  end
719
727
 
@@ -761,6 +769,8 @@ module Quonfig
761
769
  def initialize_network_mode
762
770
  raise Quonfig::Errors::InvalidSdkKeyError, @options.sdk_key if @options.sdk_key.nil? || @options.sdk_key.to_s.strip.empty?
763
771
 
772
+ warn_if_pin_ignored_in_delivery_mode
773
+
764
774
  @config_loader = Quonfig::ConfigLoader.new(@store, @options)
765
775
 
766
776
  perform_initial_fetch
@@ -791,10 +801,52 @@ module Quonfig
791
801
  if result == :failed
792
802
  handle_init_failure(RuntimeError.new('Config fetch failed against all api_urls'))
793
803
  else
804
+ sync_evaluator_env_id!
794
805
  record_refresh!
795
806
  end
796
807
  end
797
808
 
809
+ # qfg-pinh: In SDK-key DELIVERY mode the server's `meta.environment` is
810
+ # AUTHORITATIVE. The server scopes each config to a single environment and
811
+ # reports the active env id in `meta.environment` (the loader captures it
812
+ # as @config_loader.environment_id). The evaluator must always evaluate
813
+ # against that installed env id — matching sdk-go, where eval never
814
+ # branches on the pin (c.envID = envelope.Meta.Environment, quonfig.go:850).
815
+ #
816
+ # An explicit environment pin (`environment:` option / QUONFIG_ENVIRONMENT)
817
+ # is DATADIR-ONLY: in delivery mode it is IGNORED (it only feeds the datadir
818
+ # loader, which stamps meta.environment = pin). So we always adopt the
819
+ # server's env id here regardless of the pin. A WARN is emitted once at init
820
+ # (see #warn_if_pin_ignored_in_delivery_mode) when a pin is set in delivery
821
+ # mode so customers aren't surprised that it has no effect.
822
+ #
823
+ # qfg-xpln.2 originally only adopted the server env when NO pin was set,
824
+ # which let the pin win in delivery mode — qfg-pinh reverses that.
825
+ def sync_evaluator_env_id!
826
+ return unless @config_loader.respond_to?(:environment_id)
827
+
828
+ server_env = @config_loader.environment_id
829
+ @evaluator.env_id = server_env if server_env && !server_env.to_s.empty?
830
+ end
831
+
832
+ # qfg-pinh: an explicit environment pin (`environment:` option or
833
+ # QUONFIG_ENVIRONMENT) is DATADIR-ONLY. In delivery (SDK-key) mode the
834
+ # active environment is determined by the SDK key and reported via
835
+ # `meta.environment`, so the pin is ignored. Warn once at init so the
836
+ # customer isn't surprised the setting has no effect. Fired only on the
837
+ # delivery-mode init path (datadir mode honors the pin and never calls
838
+ # this).
839
+ def warn_if_pin_ignored_in_delivery_mode
840
+ env = @options.environment
841
+ return if env.nil? || env.to_s.empty?
842
+
843
+ LOG.warn(
844
+ "[quonfig] environment '#{env}' was set but the client is in delivery " \
845
+ '(SDK-key) mode; the active environment is determined by the SDK key, ' \
846
+ 'so this setting is ignored (it applies only when loading from a local data dir)'
847
+ )
848
+ end
849
+
798
850
  def handle_init_failure(err)
799
851
  if @options.on_init_failure == Quonfig::Options::ON_INITIALIZATION_FAILURE::RETURN
800
852
  LOG.warn "[quonfig] Initialization did not complete cleanly; continuing with empty store: #{err.message}"
@@ -821,6 +873,7 @@ module Quonfig
821
873
 
822
874
  begin
823
875
  @config_loader.apply_envelope(envelope)
876
+ sync_evaluator_env_id!
824
877
  handle_sse_state_change(:connected)
825
878
  record_refresh!
826
879
  rescue StandardError => e
@@ -858,6 +911,7 @@ module Quonfig
858
911
  break if stopped_ref.call
859
912
 
860
913
  @config_loader.fetch!
914
+ sync_evaluator_env_id!
861
915
  record_refresh!
862
916
  notify_delivered.call
863
917
  notify_on_update_callback
@@ -899,9 +953,7 @@ module Quonfig
899
953
  # customer's so any explicit `quonfig-user` keys win on collision.
900
954
  def build_initial_global_context(options)
901
955
  customer = normalize_context(options.global_context)
902
- enabled = options.enable_quonfig_user_context == true ||
903
- ENV['QUONFIG_DEV_CONTEXT'] == 'true'
904
- return customer unless enabled
956
+ return customer unless dev_context_enabled?(options)
905
957
 
906
958
  dev = Quonfig::DevContext.load_quonfig_user_context
907
959
  return customer if dev.nil?
@@ -909,6 +961,21 @@ module Quonfig
909
961
  merge_contexts(dev, customer)
910
962
  end
911
963
 
964
+ # Tri-state resolution for dev-context injection. Default ON, gated only
965
+ # by the presence of the tokens file (the loader no-ops without it ->
966
+ # dead in prod). Precedence: an explicit option (non-nil) wins, else
967
+ # QUONFIG_DEV_CONTEXT ('true'/'false'), else true.
968
+ def dev_context_enabled?(options)
969
+ opt = options.enable_quonfig_user_context
970
+ return opt == true unless opt.nil?
971
+
972
+ case ENV.fetch('QUONFIG_DEV_CONTEXT', nil)
973
+ when 'true' then true
974
+ when 'false' then false
975
+ else true
976
+ end
977
+ end
978
+
912
979
  def normalize_context(ctx)
913
980
  return {} if ctx.nil?
914
981
  return ctx if ctx.is_a?(Hash)
@@ -194,7 +194,9 @@ module Quonfig
194
194
  global_context: {},
195
195
  logger_key: nil,
196
196
  logger: nil,
197
- enable_quonfig_user_context: false,
197
+ # Tri-state (nil = unset). Default ON, gated only by the presence of
198
+ # ~/.quonfig/tokens.json; see Client#build_initial_global_context.
199
+ enable_quonfig_user_context: nil,
198
200
  data_dir_auto_reload: false,
199
201
  data_dir_auto_reload_debounce_ms: 200
200
202
  )
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Quonfig
4
- VERSION = '0.0.19'
4
+ VERSION = '0.0.21'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quonfig
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.19
4
+ version: 0.0.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Dwyer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-28 00:00:00.000000000 Z
11
+ date: 2026-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport