smplkit 3.0.122 → 3.0.123

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.
Files changed (23) hide show
  1. checksums.yaml +4 -4
  2. data/lib/smplkit/_generated/audit/lib/smplkit_audit_client/models/forwarder.rb +5 -17
  3. data/lib/smplkit/_generated/audit/lib/smplkit_audit_client/models/{http_configuration.rb → forwarder_http_configuration.rb} +7 -7
  4. data/lib/smplkit/_generated/audit/lib/smplkit_audit_client/models/test_forwarder_request.rb +3 -3
  5. data/lib/smplkit/_generated/audit/lib/smplkit_audit_client.rb +1 -3
  6. data/lib/smplkit/_generated/audit/spec/models/{http_configuration_spec.rb → forwarder_http_configuration_spec.rb} +6 -6
  7. data/lib/smplkit/_generated/audit/spec/models/forwarder_spec.rb +0 -6
  8. data/lib/smplkit/_generated/jobs/lib/smplkit_jobs_client/models/job.rb +2 -2
  9. data/lib/smplkit/_generated/jobs/lib/smplkit_jobs_client/models/job_http_configuration.rb +4 -4
  10. data/lib/smplkit/_generated/jobs/lib/smplkit_jobs_client.rb +0 -2
  11. data/lib/smplkit/audit/forwarders.rb +18 -24
  12. data/lib/smplkit/audit/models.rb +175 -103
  13. data/lib/smplkit/jobs/client.rb +21 -26
  14. data/lib/smplkit/jobs/models.rb +233 -273
  15. metadata +3 -11
  16. data/lib/smplkit/_generated/audit/lib/smplkit_audit_client/models/forwarder_environment.rb +0 -162
  17. data/lib/smplkit/_generated/audit/lib/smplkit_audit_client/models/http_header.rb +0 -220
  18. data/lib/smplkit/_generated/audit/spec/models/forwarder_environment_spec.rb +0 -42
  19. data/lib/smplkit/_generated/audit/spec/models/http_header_spec.rb +0 -42
  20. data/lib/smplkit/_generated/jobs/lib/smplkit_jobs_client/models/http_header.rb +0 -220
  21. data/lib/smplkit/_generated/jobs/lib/smplkit_jobs_client/models/job_environment.rb +0 -206
  22. data/lib/smplkit/_generated/jobs/spec/models/http_header_spec.rb +0 -42
  23. data/lib/smplkit/_generated/jobs/spec/models/job_environment_spec.rb +0 -66
@@ -327,26 +327,19 @@ module Smplkit
327
327
  end
328
328
  end
329
329
 
330
- # A single name/value HTTP header on a forwarder destination.
331
- #
332
- # @!attribute [rw] name
333
- # @return [String] Header name (e.g. +"Authorization"+, +"DD-API-KEY"+).
334
- # @!attribute [rw] value
335
- # @return [String] Header value. Returned in plaintext on reads, so a
336
- # get-mutate-put round-trip preserves it without re-entering secrets.
337
- HttpHeader = Struct.new(:name, :value, keyword_init: true)
338
-
339
- # Forwarder destination HTTP request shape.
330
+ # Forwarder destination HTTP request shape the base configuration.
340
331
  #
341
332
  # @!attribute [rw] method
342
333
  # @return [String] HTTP verb used for delivery. Defaults to {HttpMethod::POST}.
343
334
  # @!attribute [rw] url
344
335
  # @return [String] Destination URL the audit service sends each event to.
345
336
  # @!attribute [rw] headers
346
- # @return [Array<HttpHeader>] Headers attached to every outbound request.
347
- # Values often carry credentials and are returned in plaintext on
348
- # reads, so a get-mutate-put round-trip preserves them without
349
- # re-entering secrets.
337
+ # @return [Hash{String => String}] Headers attached to every outbound
338
+ # request, as a name→value object (e.g. +{ "DD-API-KEY" => "s3cr3t" }+).
339
+ # Use {#set_header} / {#get_header} to read and write individual headers.
340
+ # Values often carry credentials and are returned in plaintext on reads,
341
+ # so a get-mutate-put round-trip preserves them without re-entering
342
+ # secrets.
350
343
  # @!attribute [rw] success_status
351
344
  # @return [String] Status the destination must return for delivery to count
352
345
  # as success — an exact code (+"200"+, +"204"+) or a class (+"2xx"+, +"4xx"+).
@@ -374,25 +367,34 @@ module Smplkit
374
367
  success_status: "2xx", tls_verify: true, ca_cert: nil
375
368
  )
376
369
  super(
377
- method: HttpMethod.coerce(method), url: url, headers: headers || [],
370
+ method: HttpMethod.coerce(method), url: url, headers: (headers || {}).transform_keys(&:to_s),
378
371
  success_status: success_status, tls_verify: tls_verify, ca_cert: ca_cert
379
372
  )
380
373
  end
381
374
 
375
+ # Set (or replace) a single request header by name.
376
+ #
377
+ # @param name [String] Header name.
378
+ # @param value [String] Header value.
379
+ def set_header(name, value)
380
+ self.headers ||= {}
381
+ headers[name.to_s] = value
382
+ end
383
+
384
+ # The value of header +name+, or +nil+ when it is not set.
385
+ #
386
+ # @param name [String] Header name.
387
+ # @return [String, nil]
388
+ def get_header(name)
389
+ (headers || {})[name.to_s]
390
+ end
391
+
382
392
  def self.to_wire(src)
383
393
  h = src.is_a?(Hash) ? new(**src) : src
384
- SmplkitGeneratedClient::Audit::HttpConfiguration.new(
394
+ SmplkitGeneratedClient::Audit::ForwarderHttpConfiguration.new(
385
395
  method: HttpMethod.coerce(h.method),
386
396
  url: h.url,
387
- headers: (h.headers || []).map do |hdr|
388
- name, value = if hdr.is_a?(Hash)
389
- [hdr[:name] || hdr["name"],
390
- hdr[:value] || hdr["value"]]
391
- else
392
- [hdr.name, hdr.value]
393
- end
394
- SmplkitGeneratedClient::Audit::HttpHeader.new(name: name, value: value)
395
- end,
397
+ headers: (h.headers || {}).transform_keys(&:to_s),
396
398
  success_status: h.success_status,
397
399
  tls_verify: h.tls_verify,
398
400
  ca_cert: h.ca_cert
@@ -404,11 +406,13 @@ module Smplkit
404
406
 
405
407
  # Absent ``tls_verify`` on the wire means a forwarder persisted
406
408
  # before the field landed — default to verifying so its prior
407
- # secure behaviour is preserved.
409
+ # secure behaviour is preserved. Header keys arrive as symbols (the
410
+ # generated client symbolizes JSON) — stringify them so {#get_header}
411
+ # and round-trips behave by name.
408
412
  new(
409
413
  method: src.method || HttpMethod::POST,
410
414
  url: src.url || "",
411
- headers: (src.headers || []).map { |h| HttpHeader.new(name: h.name, value: h.value) },
415
+ headers: (src.headers || {}).transform_keys(&:to_s),
412
416
  success_status: src.success_status || "2xx",
413
417
  # rubocop:disable Style/RedundantCondition -- nil and false are
414
418
  # distinct: nil means "field absent on the wire" (default to true);
@@ -421,39 +425,133 @@ module Smplkit
421
425
  end
422
426
  # rubocop:enable Lint/StructNewOverride
423
427
 
424
- # Per-environment enablement and optional configuration override for a
425
- # forwarder.
428
+ # The per-environment scalar override leaves a forwarder may set (everything
429
+ # except +enabled+ and +headers+, which are addressed individually as
430
+ # +headers.<name>+). Forwarders are event-driven, so — unlike jobs — there is
431
+ # no schedule / timezone / retry_policy leaf. These map 1:1 onto
432
+ # {ForwarderEnvironment} fields and onto the flat overlay's leaf paths.
433
+ #
434
+ # @api private
435
+ FORWARDER_ENV_SCALAR_LEAVES = %i[url method success_status tls_verify ca_cert].freeze
436
+ # The same leaves as wire-key strings, for parsing the flat overlay.
437
+ #
438
+ # @api private
439
+ FORWARDER_ENV_SCALAR_LEAF_NAMES = FORWARDER_ENV_SCALAR_LEAVES.map(&:to_s).freeze
440
+
441
+ # One environment's *sparse override* for a forwarder (ADR-056).
442
+ #
443
+ # A forwarder's {Forwarder#environments} map holds one of these per
444
+ # environment. Only the leaves you set are sent on save; everything you leave
445
+ # unset is inherited from the forwarder's base definition, and the server
446
+ # resolves base ⊕ overrides when an event is delivered. The base definition
447
+ # delivers nowhere, so a forwarder delivers in an environment only when that
448
+ # environment's override sets +enabled: true+.
426
449
  #
427
- # A forwarder delivers events in a given environment only when that
428
- # environment has an entry in {Forwarder#environments} with
429
- # +enabled: true+. An environment with no entry (or +enabled: false+)
430
- # receives no deliveries.
450
+ # Reach one through {Forwarder#environment}, e.g.
451
+ # +forwarder.environment("production").url = "https://prod.siem.example.com/in"+.
452
+ #
453
+ # *Reading a leaf returns this environment's override, or +nil+ when it does
454
+ # not override that leaf* — the SDK does not merge in the base value
455
+ # (forwarders resolve server-side). To see a base value, read the forwarder's
456
+ # base definition ({Forwarder#configuration}).
431
457
  #
432
458
  # @!attribute [rw] enabled
433
459
  # @return [Boolean] Whether the forwarder delivers events in this
434
460
  # environment. Defaults to +false+.
435
- # @!attribute [rw] configuration
436
- # @return [HttpConfiguration, nil] Optional per-environment destination
437
- # configuration that fully replaces the forwarder's base
438
- # {Forwarder#configuration} for this environment. +nil+ (the default)
439
- # inherits the base configuration. As with the base configuration,
440
- # header values are returned in plaintext on reads, so a get-mutate-put
441
- # round-trip preserves them without re-entering secrets.
442
- ForwarderEnvironment = Struct.new(:enabled, :configuration, keyword_init: true) do
443
- def initialize(enabled: false, configuration: nil)
444
- super
461
+ # @!attribute [rw] url
462
+ # @return [String, nil] Per-environment URL override. +nil+ inherits the base.
463
+ # @!attribute [rw] method
464
+ # @return [String, nil] Per-environment HTTP-method override. +nil+ inherits the base.
465
+ # @!attribute [rw] success_status
466
+ # @return [String, nil] Per-environment success-status override. +nil+ inherits the base.
467
+ # @!attribute [rw] tls_verify
468
+ # @return [Boolean, nil] Per-environment TLS-verify override. +nil+ inherits the base.
469
+ # @!attribute [rw] ca_cert
470
+ # @return [String, nil] Per-environment CA-cert override. +nil+ inherits the base.
471
+ # @!attribute [rw] headers
472
+ # @return [Hash{String => String}] Per-environment header overrides, as a
473
+ # name→value object. Each entry overrides (or adds) that one header by name
474
+ # on top of the base headers, leaving the rest inherited. Use {#set_header}
475
+ # / {#get_header}.
476
+ #
477
+ # rubocop:disable Lint/StructNewOverride -- ``:method`` matches the
478
+ # API attribute and shadowing Struct#method is the expected ergonomics.
479
+ ForwarderEnvironment = Struct.new(
480
+ :enabled, :url, :method, :success_status, :tls_verify, :ca_cert, :headers,
481
+ keyword_init: true
482
+ ) do
483
+ def initialize(enabled: false, url: nil, method: nil, success_status: nil,
484
+ tls_verify: nil, ca_cert: nil, headers: nil)
485
+ super(
486
+ enabled: enabled, url: url, method: method, success_status: success_status,
487
+ tls_verify: tls_verify, ca_cert: ca_cert, headers: (headers || {}).transform_keys(&:to_s)
488
+ )
445
489
  end
446
490
 
447
- def self.from_wire(src)
448
- return new if src.nil?
491
+ # Override (or add) a single header by name in this environment.
492
+ #
493
+ # @param name [String] Header name.
494
+ # @param value [String] Header value.
495
+ def set_header(name, value)
496
+ self.headers ||= {}
497
+ headers[name.to_s] = value
498
+ end
499
+
500
+ # This environment's override for header +name+, or +nil+ when it does not
501
+ # override that header.
502
+ #
503
+ # @param name [String] Header name.
504
+ # @return [String, nil]
505
+ def get_header(name)
506
+ (headers || {})[name.to_s]
507
+ end
508
+
509
+ # @api private — Emit the flat sparse leaf-path overlay (ADR-056): +enabled+
510
+ # plus only the leaves this environment overrides, with each header as a
511
+ # +headers.<name>+ leaf.
512
+ #
513
+ # @return [Hash{String => Object}]
514
+ def to_payload
515
+ payload = { "enabled" => enabled }
516
+ FORWARDER_ENV_SCALAR_LEAVES.each do |leaf|
517
+ value = self[leaf]
518
+ payload[leaf.to_s] = value unless value.nil?
519
+ end
520
+ (headers || {}).each { |name, value| payload["headers.#{name}"] = value }
521
+ payload
522
+ end
449
523
 
450
- cfg = src.configuration
524
+ # @api private — Parse the flat leaf-path overlay the server returns
525
+ # (ADR-056). Header leaves arrive as +headers.<name>+ (split on the first
526
+ # dot, so a dotted header name like +X-Foo.Bar+ is preserved); every other
527
+ # leaf is a single top-level key. Unknown leaves are ignored for forward
528
+ # compatibility. Keys may be symbols or strings.
529
+ #
530
+ # @param raw [Hash, nil] The flat overlay hash, or +nil+ for an empty override.
531
+ # @return [ForwarderEnvironment]
532
+ def self.from_flat(raw)
533
+ return new if raw.nil?
534
+
535
+ headers = {}
536
+ scalars = {}
537
+ (raw || {}).each do |key, value|
538
+ key = key.to_s
539
+ group, _dot, name = key.partition(".")
540
+ if group == "headers" && !name.empty?
541
+ headers[name] = value
542
+ elsif FORWARDER_ENV_SCALAR_LEAF_NAMES.include?(key) || key == "enabled"
543
+ scalars[key] = value
544
+ end
545
+ end
451
546
  new(
452
- enabled: src.enabled.nil? ? false : src.enabled,
453
- configuration: cfg.nil? ? nil : HttpConfiguration.from_wire(cfg)
547
+ enabled: scalars["enabled"] ? true : false,
548
+ url: scalars["url"], method: scalars["method"],
549
+ success_status: scalars["success_status"], tls_verify: scalars["tls_verify"],
550
+ ca_cert: scalars["ca_cert"], headers: headers
454
551
  )
455
552
  end
456
553
  end
554
+ # rubocop:enable Lint/StructNewOverride
457
555
 
458
556
  # A SIEM streaming forwarder configured on the customer's account.
459
557
  #
@@ -476,11 +574,13 @@ module Smplkit
476
574
  # @return [String] One of {ForwarderType::VALUES}.
477
575
  attr_accessor :forwarder_type
478
576
 
479
- # @return [Boolean] Read-only. Always +false+ the base enablement is
480
- # pinned off. Whether a forwarder actually delivers is decided per
481
- # environment via {#environments}; mutating this field has no effect on
482
- # the server.
483
- attr_accessor :enabled
577
+ # @return [Boolean] Read-only roll-up: +true+ when the forwarder is enabled
578
+ # in at least one environment. Derived from {#environments} there is no
579
+ # server-side top-level +enabled+ field. Enable per environment via
580
+ # +forwarder.environment(env).enabled = true+.
581
+ def enabled
582
+ (@environments || {}).each_value.any?(&:enabled)
583
+ end
484
584
 
485
585
  # @return [Boolean] When +true+, this forwarder also receives platform
486
586
  # change events that smplkit records about your own resources (flag,
@@ -492,12 +592,12 @@ module Smplkit
492
592
  # not tied to a deployment environment.
493
593
  attr_accessor :forward_smplkit_events
494
594
 
495
- # @return [Hash{String => ForwarderEnvironment}] Per-environment overrides
496
- # keyed by environment key (e.g. +"production"+, +"staging"+). A
595
+ # @return [Hash{String => ForwarderEnvironment}] Per-environment sparse
596
+ # overrides keyed by environment key (e.g. +"production"+, +"staging"+). A
497
597
  # forwarder delivers in an environment only when
498
- # +environments[env].enabled+ is +true+. Each entry may carry an optional
499
- # {HttpConfiguration} override; omit it to inherit the base
500
- # {#configuration}. Every referenced environment must exist and be
598
+ # +environments[env].enabled+ is +true+. Each entry overrides only the
599
+ # leaves it sets; omitted leaves inherit the base {#configuration}. Reach
600
+ # one via {#environment}. Every referenced environment must exist and be
501
601
  # managed for the account.
502
602
  attr_accessor :environments
503
603
 
@@ -536,7 +636,7 @@ module Smplkit
536
636
  attr_accessor :version
537
637
 
538
638
  def initialize(client = nil, name:, forwarder_type:, configuration:,
539
- id: nil, enabled: false, forward_smplkit_events: false,
639
+ id: nil, forward_smplkit_events: false,
540
640
  environments: nil, description: nil,
541
641
  filter: nil, transform: nil, transform_type: nil,
542
642
  created_at: nil, updated_at: nil, deleted_at: nil, version: nil)
@@ -545,10 +645,6 @@ module Smplkit
545
645
  @name = name
546
646
  @forwarder_type = ForwarderType.coerce(forwarder_type)
547
647
  @configuration = configuration
548
- # ``enabled`` is server-pinned false; we keep the attribute so reads
549
- # round-trip the server value, but enablement is driven by
550
- # ``environments`` (see the class docstring).
551
- @enabled = enabled
552
648
  @forward_smplkit_events = forward_smplkit_events
553
649
  @environments = environments || {}
554
650
  @description = description
@@ -593,44 +689,23 @@ module Smplkit
593
689
  end
594
690
  alias delete! delete
595
691
 
596
- # Set this forwarder's destination configuration in memory.
692
+ # The per-environment override for +environment+ the single place to read
693
+ # or set what this forwarder overrides there (ADR-056).
597
694
  #
598
- # With +environment+ omitted, replaces the base {#configuration}. With
599
- # +environment+ given, sets the per-environment override's configuration
600
- # on {#environments}, creating the override entry if it doesn't exist yet
601
- # (preserving any already-set +enabled+ on it). Call {#save} to persist.
602
- def set_configuration(configuration, environment: nil)
603
- if environment.nil?
604
- @configuration = configuration
605
- else
606
- _environment_override(environment).configuration = configuration
607
- end
608
- end
609
-
610
- # Set this forwarder's enablement in memory.
695
+ # Returns the {ForwarderEnvironment} for +environment+, creating an empty
696
+ # one (and inserting it into {#environments}) on first access, so you can
697
+ # set overrides directly:
611
698
  #
612
- # With +environment+ omitted, sets the base {#enabled} (which the server
613
- # pins false regardless — enablement is per-environment). With
614
- # +environment+ given, sets the per-environment override's +enabled+ on
615
- # {#environments}, creating the override entry if it doesn't exist yet
616
- # (preserving any already-set +configuration+ on it). Call {#save} to
617
- # persist.
618
- def set_enabled(enabled, environment: nil)
619
- if environment.nil?
620
- @enabled = enabled
621
- else
622
- _environment_override(environment).enabled = enabled
623
- end
624
- end
625
-
626
- # Return the override for +environment+, creating an empty one if absent.
699
+ # forwarder.environment("production").enabled = true
700
+ # forwarder.environment("production").url = "https://prod.siem.example.com/in"
701
+ # forwarder.environment("production").set_header("DD-API-KEY", "prod-secret")
627
702
  #
628
- # The per-environment mutators reach through here so an existing
629
- # override's other field is preserved when only one of +enabled+ /
630
- # +configuration+ is being set.
703
+ # Only the leaves you set are sent on save; everything else inherits the
704
+ # base definition (the server resolves base overrides on delivery).
631
705
  #
632
- # @api private
633
- def _environment_override(environment)
706
+ # @param environment [String] The environment key.
707
+ # @return [ForwarderEnvironment]
708
+ def environment(environment)
634
709
  @environments[environment] ||= ForwarderEnvironment.new
635
710
  end
636
711
 
@@ -640,7 +715,6 @@ module Smplkit
640
715
  @name = other.name
641
716
  @forwarder_type = other.forwarder_type
642
717
  @configuration = other.configuration
643
- @enabled = other.enabled
644
718
  @forward_smplkit_events = other.forward_smplkit_events
645
719
  @environments = other.environments
646
720
  @description = other.description
@@ -676,7 +750,7 @@ module Smplkit
676
750
  def self.from_resource(resource, client: nil)
677
751
  a = resource.attributes
678
752
  environments = (a.environments || {}).each_with_object({}) do |(env_key, env_raw), out|
679
- out[env_key.to_s] = ForwarderEnvironment.from_wire(env_raw)
753
+ out[env_key.to_s] = ForwarderEnvironment.from_flat(env_raw)
680
754
  end
681
755
  new(
682
756
  client,
@@ -684,10 +758,8 @@ module Smplkit
684
758
  name: a.name,
685
759
  description: a.description,
686
760
  forwarder_type: a.forwarder_type,
687
- # The base ``enabled`` is server-pinned false; round-trip whatever
688
- # the server returned (always false) without assuming a default of
689
- # true.
690
- enabled: a.enabled.nil? ? false : a.enabled,
761
+ # The base ``enabled`` roll-up is derived from ``environments``, not
762
+ # read from the wire the API has no top-level ``enabled``.
691
763
  # ``forward_smplkit_events`` defaults to false; a forwarder persisted
692
764
  # before the field landed reads back as not opted in.
693
765
  forward_smplkit_events: a.forward_smplkit_events.nil? ? false : a.forward_smplkit_events,
@@ -113,9 +113,10 @@ module Smplkit
113
113
  # policies.
114
114
  #
115
115
  # A {RetryPolicy} is an active record: build one with {#new}, set fields, and
116
- # call +#save+; then reference it from a job's +retry_policy+ (see
117
- # {JobsClient#new_recurring_job} and {Job#set_retry_policy}). Retry policies
118
- # are account-global never environment-scoped.
116
+ # call +#save+; then reference it from a job's +retry_policy+ — base:
117
+ # +job.retry_policy = policy+; per-environment:
118
+ # +job.environment(env).retry_policy = policy+. Retry policies are
119
+ # account-global — never environment-scoped.
119
120
  class RetryPoliciesClient
120
121
  # @param api [SmplkitGeneratedClient::Jobs::RetryPoliciesApi] The generated
121
122
  # retry-policies API.
@@ -380,11 +381,12 @@ module Smplkit
380
381
  # sends each time it fires.
381
382
  # @param description [String, nil] Optional free-text description.
382
383
  # @param environments [Hash{String => Smplkit::Jobs::JobEnvironment, Hash}, nil]
383
- # Per-environment overrides keyed by environment key — each a
384
- # {Smplkit::Jobs::JobEnvironment}, or a plain hash (+{ enabled: true }+,
385
- # optionally with a +:schedule+ cron override and/or a +:configuration+
386
- # {Smplkit::Jobs::HttpConfig} override). The job is scheduled only in
387
- # environments enabled here.
384
+ # Per-environment sparse overrides keyed by environment key — each a
385
+ # {Smplkit::Jobs::JobEnvironment}, or a plain hash of its constructor kwargs
386
+ # (+{ enabled: true }+, optionally with +:schedule+, +:timezone+,
387
+ # +:retry_policy+, request leaves like +:url+, and a +:headers+ name→value
388
+ # map). Each entry overrides only the leaves it sets; the job is scheduled
389
+ # only in environments enabled here.
388
390
  # @param concurrency_policy [String] How overlapping runs are handled.
389
391
  # Defaults to +"ALLOW"+.
390
392
  # @return [Smplkit::Jobs::Job]
@@ -411,10 +413,11 @@ module Smplkit
411
413
  # sends each time it runs.
412
414
  # @param description [String, nil] Optional free-text description.
413
415
  # @param environments [Hash{String => Smplkit::Jobs::JobEnvironment, Hash}, nil]
414
- # Per-environment overrides keyed by environment key — each a
415
- # {Smplkit::Jobs::JobEnvironment}, or a plain hash (+{ enabled: true }+,
416
- # optionally with a +:configuration+ {Smplkit::Jobs::HttpConfig}
417
- # override). The job is triggerable only in environments enabled here.
416
+ # Per-environment sparse overrides keyed by environment key — each a
417
+ # {Smplkit::Jobs::JobEnvironment}, or a plain hash of its constructor kwargs
418
+ # (+{ enabled: true }+, optionally with request leaves like +:url+ and a
419
+ # +:headers+ name→value map). Each entry overrides only the leaves it sets;
420
+ # the job is triggerable only in environments enabled here.
418
421
  # @param concurrency_policy [String] How overlapping runs are handled.
419
422
  # Defaults to +"ALLOW"+.
420
423
  # @param retry_policy [String, nil] Retry policy for failed runs — the id of
@@ -583,22 +586,14 @@ module Smplkit
583
586
  )
584
587
  end
585
588
 
586
- # Convert the wrapper +environments+ map to the generated model hash.
587
- #
588
- # Each entry's +enabled+ is always written; a per-environment +schedule+
589
- # (cron) override, +timezone+ override, +retry_policy+ override, and
590
- # +configuration+ override are each sent only when present (omit to inherit
591
- # the job's base +schedule+ / +timezone+ / +retry_policy+ /
592
- # +configuration+). The read-only per-environment +next_run_at+ is never
593
- # written.
589
+ # Convert the wrapper +environments+ map to the flat per-environment overlay
590
+ # the generated +Job+ model carries (ADR-056). Each value is the
591
+ # environment's sparse leaf-path overlay: +enabled+ plus only the leaves it
592
+ # overrides, with each header as a +headers.<name>+ leaf. The read-only
593
+ # per-environment +next_run_at+ is never written.
594
594
  def environments_to_wire(environments)
595
595
  (environments || {}).each_with_object({}) do |(env_key, env), out|
596
- attrs = { enabled: env.enabled }
597
- attrs[:schedule] = env.schedule unless env.schedule.nil?
598
- attrs[:timezone] = env.timezone unless env.timezone.nil?
599
- attrs[:retry_policy] = env.retry_policy unless env.retry_policy.nil?
600
- attrs[:configuration] = HttpConfig.to_wire(env.configuration) unless env.configuration.nil?
601
- out[env_key.to_s] = SmplkitGeneratedClient::Jobs::JobEnvironment.new(attrs)
596
+ out[env_key.to_s] = env.to_payload
602
597
  end
603
598
  end
604
599