command_tower 0.16.0 → 0.18.0

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -8
  3. data/app/controllers/command_tower/application_controller.rb +1 -0
  4. data/app/controllers/command_tower/me/inbox_controller.rb +16 -0
  5. data/app/controllers/concerns/command_tower/execution/client_compatibility_boundary.rb +39 -0
  6. data/app/deserializers/command_tower/deserializers/messaging/inbox.rb +85 -0
  7. data/app/errors/command_tower/errors/client_update_required_error.rb +27 -0
  8. data/app/jobs/command_tower/messaging/communications/produce_recipient_job.rb +2 -0
  9. data/app/models/command_tower/messaging/communication.rb +31 -0
  10. data/app/serializers/command_tower/serializers/messaging/inbox.rb +45 -1
  11. data/app/services/command_tower/email_theme/resolver.rb +45 -0
  12. data/app/services/command_tower/messaging/accept/coordinator.rb +16 -1
  13. data/app/services/command_tower/messaging/accept/persister.rb +13 -0
  14. data/app/services/command_tower/messaging/contract/mappers/communication_mapper.rb +7 -0
  15. data/app/services/command_tower/messaging/contract/results/communication_result.rb +1 -0
  16. data/app/services/command_tower/messaging/inbox/conversation_result.rb +31 -0
  17. data/app/services/command_tower/messaging/inbox/entry_result.rb +36 -0
  18. data/app/services/command_tower/messaging/inbox/reader.rb +231 -18
  19. data/app/services/command_tower/messaging/inbox.rb +4 -0
  20. data/app/services/command_tower/messaging/notification_types/declaration.rb +14 -1
  21. data/app/services/command_tower/messaging/rendering/channel_renderer.rb +44 -13
  22. data/app/services/command_tower/messaging/rendering/inbox_document.rb +131 -0
  23. data/app/services/command_tower/messaging/rendering/inbox_document_renderer.rb +224 -0
  24. data/app/services/command_tower/messaging/rendering/inbox_presentation_resolver.rb +52 -0
  25. data/app/services/command_tower/messaging/rendering/inbox_presentation_snapshot.rb +64 -0
  26. data/app/services/command_tower/messaging/rendering/template_resolver.rb +128 -0
  27. data/app/services/command_tower/messaging.rb +5 -1
  28. data/app/services/command_tower/services/client_compatibility/evaluate.rb +219 -0
  29. data/app/services/command_tower/services/messaging/communications/produce.rb +4 -0
  30. data/app/services/command_tower/services/messaging/communications/produce_many.rb +6 -0
  31. data/app/services/command_tower/services/messaging/inbox.rb +55 -2
  32. data/app/views/command_tower/email_verification_mailer/verify_email.html.erb +18 -17
  33. data/app/views/command_tower/messaging/rendering/email.html.erb +6 -5
  34. data/app/views/command_tower/password_reset_mailer/reset_password.html.erb +24 -23
  35. data/app/workflows/command_tower/workflows/auth/plain_text/login_workflow.rb +3 -0
  36. data/app/workflows/command_tower/workflows/auth/session/show_workflow.rb +3 -0
  37. data/app/workflows/command_tower/workflows/client_compatibility/evaluate_workflow.rb +83 -0
  38. data/app/workflows/command_tower/workflows/client_compatibility/recommendation_meta.rb +25 -0
  39. data/app/workflows/command_tower/workflows/messaging/communications/produce_recipient_workflow.rb +5 -1
  40. data/app/workflows/command_tower/workflows/messaging/inbox.rb +15 -1
  41. data/config/routes.rb +1 -0
  42. data/db/migrate/20261010000001_add_inbox_presentation_snapshot_to_messaging_communications.rb +7 -0
  43. data/db/migrate/20261010000002_add_conversation_identity_to_messaging_communications.rb +10 -0
  44. data/docs/api_reference.md +13 -2
  45. data/docs/authorization.md +1 -1
  46. data/docs/bootstrap/00-ownership.md +77 -0
  47. data/docs/bootstrap/01-docker-make-compose.md +267 -0
  48. data/docs/bootstrap/02-create-the-rails-app.md +75 -0
  49. data/docs/bootstrap/03-pin-the-gem.md +53 -0
  50. data/docs/bootstrap/04-secrets-and-env.md +59 -0
  51. data/docs/bootstrap/05-install-migrate-doctor.md +74 -0
  52. data/docs/bootstrap/06-mount-and-health.md +53 -0
  53. data/docs/bootstrap/07-execution-bases.md +38 -0
  54. data/docs/bootstrap/08-initializer.md +90 -0
  55. data/docs/bootstrap/09-rbac.md +83 -0
  56. data/docs/bootstrap/10-roles-and-gates.md +62 -0
  57. data/docs/bootstrap/11-auth-client-path.md +57 -0
  58. data/docs/bootstrap/12-smoke-check.md +81 -0
  59. data/docs/bootstrap/13-optional.md +50 -0
  60. data/docs/bootstrap/14-sanity-checks.md +44 -0
  61. data/docs/bootstrap/README.md +90 -0
  62. data/docs/cookie_authentication_guide.md +11 -0
  63. data/docs/extending.md +5 -4
  64. data/docs/host_integration_guide.md +3 -246
  65. data/docs/initializing.md +37 -28
  66. data/docs/messaging_integration_guide.md +39 -1
  67. data/docs/principal_capabilities.md +1 -1
  68. data/docs/upgrades/0.10.0.md +5 -5
  69. data/docs/upgrades/0.11.0.md +5 -5
  70. data/docs/upgrades/0.17.0.md +33 -0
  71. data/docs/upgrades/0.18.0.md +35 -0
  72. data/docs/upgrades/README.md +3 -1
  73. data/lib/command_tower/authorization/default.yml +1 -0
  74. data/lib/command_tower/client_compatibility/version.rb +45 -0
  75. data/lib/command_tower/client_compatibility.rb +23 -0
  76. data/lib/command_tower/configuration/config.rb +6 -0
  77. data/lib/command_tower/configuration/email_theme/config.rb +69 -0
  78. data/lib/command_tower/configuration/registry/client_compatibility/binding_definition.rb +42 -0
  79. data/lib/command_tower/configuration/registry/client_compatibility/config.rb +353 -0
  80. data/lib/command_tower/configuration/registry/client_compatibility/contract_definition.rb +16 -0
  81. data/lib/command_tower/configuration/registry/client_compatibility/entity_requirement_definition.rb +67 -0
  82. data/lib/command_tower/configuration/registry/client_compatibility/minimum_overrides.rb +46 -0
  83. data/lib/command_tower/configuration/registry/client_compatibility/platform_definition.rb +66 -0
  84. data/lib/command_tower/configuration/registry/config.rb +14 -0
  85. data/lib/command_tower/configuration/registry/inbox_presentations/config.rb +105 -0
  86. data/lib/command_tower/configuration/registry/inbox_presentations/presentation_definition.rb +71 -0
  87. data/lib/command_tower/current.rb +1 -0
  88. data/lib/command_tower/engine.rb +4 -0
  89. data/lib/command_tower/inbox_presentations.rb +19 -0
  90. data/lib/command_tower/install/baseline.rb +2 -0
  91. data/lib/command_tower/version.rb +1 -1
  92. metadata +47 -2
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "class_composer"
4
+
5
+ module CommandTower
6
+ module Configuration
7
+ module Registry
8
+ module InboxPresentations
9
+ class PresentationDefinition
10
+ include ClassComposer::Generator
11
+
12
+ add_composer :composer_class,
13
+ desc: "String class name of the registered presentation composer " \
14
+ "(`.call(communication:, recipient_id:) -> Hash`), resolved via `.constantize` " \
15
+ "at InboxDocumentRenderer render time — never at registration time",
16
+ allowed: String,
17
+ default: ""
18
+
19
+ # Explicit output projection (Rich Messaging corrective slice —
20
+ # ServiceResult/context leak fix). `InboxDocumentRenderer#presentation_block`
21
+ # slices the composer's raw result down to exactly these keys before
22
+ # it ever reaches `content.blocks[].data` — every other key (declared
23
+ # `ApplicationService` inputs, incidental intermediate context state,
24
+ # or anything else a composer happens to set) is dropped
25
+ # unconditionally, regardless of whether the composer is an
26
+ # `ApplicationService` or a plain Hash-returning class. This is a
27
+ # declared allow-list owned by the registration, not an inference
28
+ # from `ServiceResult`/`ApplicationService` argument metadata.
29
+ add_composer :output_keys,
30
+ desc: "Array of Symbol keys that are the ONLY keys copied from the composer's " \
31
+ "result onto the Inbox wire (`content.blocks[].data`) — every other " \
32
+ "context/result key (composer inputs, intermediate state, anything else) " \
33
+ "is dropped at render time, regardless of composer shape",
34
+ allowed: Array,
35
+ default: []
36
+
37
+ attr_accessor :owner, :id
38
+
39
+ def validate_definition!(key:)
40
+ self.id = key.to_s
41
+ self.owner = owner&.to_sym || :host
42
+ self.composer_class = require_present_string!(composer_class, field: "composer_class", key:)
43
+ self.output_keys = require_present_output_keys!(output_keys, key:)
44
+ end
45
+
46
+ private
47
+
48
+ def require_present_string!(value, field:, key:)
49
+ text = value.to_s.strip
50
+ if text.empty?
51
+ raise CommandTower::InboxPresentations::InvalidPresentationDefinitionError,
52
+ "inbox presentation #{key} is missing #{field}"
53
+ end
54
+
55
+ text
56
+ end
57
+
58
+ def require_present_output_keys!(value, key:)
59
+ keys = Array(value).map { |entry| entry.to_s.strip }
60
+ if keys.empty? || keys.any?(&:empty?)
61
+ raise CommandTower::InboxPresentations::InvalidPresentationDefinitionError,
62
+ "inbox presentation #{key} is missing output_keys"
63
+ end
64
+
65
+ keys.map(&:to_sym)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -15,5 +15,6 @@ module CommandTower
15
15
  attribute :impersonation_activity_recorded, default: false
16
16
  attribute :remote_ip
17
17
  attribute :user_agent
18
+ attribute :client_compatibility_recommendation
18
19
  end
19
20
  end
@@ -22,12 +22,15 @@ module CommandTower
22
22
  # ensure defaults are instantiated and all variables are assigned
23
23
  CommandTower.config.class_composer_assign_defaults!(children: true)
24
24
  CommandTower::CredentialResolution::SmtpActionMailerBridge.apply!
25
+ CommandTower.config.registry.client_compatibility.apply_env_overlay!
25
26
 
26
27
  unless Rails.env.test?
27
28
  CommandTower.config.impersonation.validate!
28
29
  CommandTower.config.registry.audit.finalize!
29
30
  CommandTower.config.registry.admin_workspace.finalize!
30
31
  CommandTower.config.registry.principal_capabilities.finalize!
32
+ CommandTower.config.registry.client_compatibility.finalize!
33
+ CommandTower.config.registry.inbox_presentations.finalize!
31
34
  CommandTower.config.admin_scope.finalize!
32
35
  # Now that we can confirm all variables are defined, freeze all objects an their children
33
36
  CommandTower.config.class_composer_freeze_objects!(behavior: :raise, children: true)
@@ -62,6 +65,7 @@ module CommandTower
62
65
  entities = CommandTower::Authorization::Entity.entities
63
66
  CommandTower.config.registry.admin_workspace.validate_required_entities!(entities)
64
67
  CommandTower.config.registry.principal_capabilities.validate_required_entities!(entities)
68
+ CommandTower.config.registry.client_compatibility.validate!(entities)
65
69
  CommandTower.config.admin_scope.validate_scoped_tools!
66
70
  end
67
71
  CommandTower::Logging::Subscriber.attach!
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CommandTower
4
+ # Rich Messaging Slice 2.5 — registry of registered Inbox presentation
5
+ # capabilities (semantic keys such as `pickem.make_picks`) mapped to a
6
+ # trusted, host- or CommandTower-owned composer class. See
7
+ # artifacts/visual-improvements/rich-messaging/authority/RICH_MESSAGING_PRESENTATION_AUTHORITY.md
8
+ # Part I and
9
+ # artifacts/visual-improvements/rich-messaging/authority/RICH_MESSAGING_RUBY_INBOX_DEFINITION_DISCOVERY.md §9.
10
+ module InboxPresentations
11
+ class Error < CommandTower::Error; end
12
+
13
+ class UnregisteredCapabilityError < Error; end
14
+ class DuplicateCapabilityError < Error; end
15
+ class InvalidKeyError < Error; end
16
+ class InvalidPresentationDefinitionError < Error; end
17
+ class FrozenRegistryError < Error; end
18
+ end
19
+ end
@@ -16,6 +16,8 @@ module CommandTower
16
16
  20260817000003_create_command_tower_impersonation_sessions.rb
17
17
  20260826140000_add_deleted_at_to_users.rb
18
18
  20260906180000_create_user_experience_states.rb
19
+ 20261010000001_add_inbox_presentation_snapshot_to_messaging_communications.rb
20
+ 20261010000002_add_conversation_identity_to_messaging_communications.rb
19
21
  ].freeze
20
22
 
21
23
  module_function
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CommandTower
4
- VERSION = "0.16.0"
4
+ VERSION = "0.18.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: command_tower
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - matt-taylor
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-07 00:00:00.000000000 Z
11
+ date: 2026-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phonelib
@@ -231,6 +231,7 @@ files:
231
231
  - app/controllers/concerns/command_tower/auth/invalid_credentials_deserializer_renderer.rb
232
232
  - app/controllers/concerns/command_tower/auth/password_recovery_session_boundary.rb
233
233
  - app/controllers/concerns/command_tower/auth/signup_session_boundary.rb
234
+ - app/controllers/concerns/command_tower/execution/client_compatibility_boundary.rb
234
235
  - app/controllers/concerns/command_tower/execution/http_boundary.rb
235
236
  - app/deserializers/command_tower/deserializers/admin/messaging/create_announcement_deserializer.rb
236
237
  - app/deserializers/command_tower/deserializers/admin/scope_parameter.rb
@@ -309,6 +310,7 @@ files:
309
310
  - app/errors/command_tower/errors/auth/signup_session_rate_limit_error.rb
310
311
  - app/errors/command_tower/errors/auth/verification_code_invalid_error.rb
311
312
  - app/errors/command_tower/errors/auth/verification_send_failed_error.rb
313
+ - app/errors/command_tower/errors/client_update_required_error.rb
312
314
  - app/errors/command_tower/errors/continuation_exhausted_error.rb
313
315
  - app/errors/command_tower/errors/forbidden_error.rb
314
316
  - app/errors/command_tower/errors/internal_error.rb
@@ -409,6 +411,7 @@ files:
409
411
  - app/services/command_tower/clients/transport/request.rb
410
412
  - app/services/command_tower/clients/transport/response.rb
411
413
  - app/services/command_tower/clients/url.rb
414
+ - app/services/command_tower/email_theme/resolver.rb
412
415
  - app/services/command_tower/identity/phone/normalizer.rb
413
416
  - app/services/command_tower/identity/phone_verification/sms_configuration.rb
414
417
  - app/services/command_tower/identity/phone_verification/sms_transport.rb
@@ -524,6 +527,8 @@ files:
524
527
  - app/services/command_tower/messaging/handoff/recovery.rb
525
528
  - app/services/command_tower/messaging/inbox.rb
526
529
  - app/services/command_tower/messaging/inbox/bulk_result.rb
530
+ - app/services/command_tower/messaging/inbox/conversation_result.rb
531
+ - app/services/command_tower/messaging/inbox/entry_result.rb
527
532
  - app/services/command_tower/messaging/inbox/error.rb
528
533
  - app/services/command_tower/messaging/inbox/invalid_bulk_items_error.rb
529
534
  - app/services/command_tower/messaging/inbox/invariant_error.rb
@@ -592,11 +597,16 @@ files:
592
597
  - app/services/command_tower/messaging/recipient_readiness/recipient_result.rb
593
598
  - app/services/command_tower/messaging/recipient_readiness/unknown_channel_error.rb
594
599
  - app/services/command_tower/messaging/rendering/channel_renderer.rb
600
+ - app/services/command_tower/messaging/rendering/inbox_document.rb
601
+ - app/services/command_tower/messaging/rendering/inbox_document_renderer.rb
602
+ - app/services/command_tower/messaging/rendering/inbox_presentation_resolver.rb
603
+ - app/services/command_tower/messaging/rendering/inbox_presentation_snapshot.rb
595
604
  - app/services/command_tower/messaging/rendering/render_error.rb
596
605
  - app/services/command_tower/messaging/rendering/rendered_payload.rb
597
606
  - app/services/command_tower/messaging/rendering/rendered_push_payload.rb
598
607
  - app/services/command_tower/messaging/rendering/rendered_pushover_payload.rb
599
608
  - app/services/command_tower/messaging/rendering/rendered_sms_payload.rb
609
+ - app/services/command_tower/messaging/rendering/template_resolver.rb
600
610
  - app/services/command_tower/secrets.rb
601
611
  - app/services/command_tower/secrets/cleanse.rb
602
612
  - app/services/command_tower/secrets/generate.rb
@@ -660,6 +670,7 @@ files:
660
670
  - app/services/command_tower/services/auth/signup_session/validate.rb
661
671
  - app/services/command_tower/services/auth/tombstone_user.rb
662
672
  - app/services/command_tower/services/auth/username_availability.rb
673
+ - app/services/command_tower/services/client_compatibility/evaluate.rb
663
674
  - app/services/command_tower/services/impersonation/create.rb
664
675
  - app/services/command_tower/services/impersonation/end.rb
665
676
  - app/services/command_tower/services/impersonation/record_activity.rb
@@ -737,6 +748,8 @@ files:
737
748
  - app/workflows/command_tower/workflows/auth/signup_session/authenticate_workflow.rb
738
749
  - app/workflows/command_tower/workflows/auth/signup_session/create_workflow.rb
739
750
  - app/workflows/command_tower/workflows/auth/username_availability_workflow.rb
751
+ - app/workflows/command_tower/workflows/client_compatibility/evaluate_workflow.rb
752
+ - app/workflows/command_tower/workflows/client_compatibility/recommendation_meta.rb
740
753
  - app/workflows/command_tower/workflows/impersonation/error_mapping.rb
741
754
  - app/workflows/command_tower/workflows/impersonation/start_workflow.rb
742
755
  - app/workflows/command_tower/workflows/impersonation/stop_workflow.rb
@@ -785,6 +798,8 @@ files:
785
798
  - db/migrate/20260817000003_create_command_tower_impersonation_sessions.rb
786
799
  - db/migrate/20260826140000_add_deleted_at_to_users.rb
787
800
  - db/migrate/20260906180000_create_user_experience_states.rb
801
+ - db/migrate/20261010000001_add_inbox_presentation_snapshot_to_messaging_communications.rb
802
+ - db/migrate/20261010000002_add_conversation_identity_to_messaging_communications.rb
788
803
  - docs/admin_workspace.md
789
804
  - docs/api_reference.md
790
805
  - docs/architecture.md
@@ -792,6 +807,22 @@ files:
792
807
  - docs/authentication.md
793
808
  - docs/authentication_authorization_guide.md
794
809
  - docs/authorization.md
810
+ - docs/bootstrap/00-ownership.md
811
+ - docs/bootstrap/01-docker-make-compose.md
812
+ - docs/bootstrap/02-create-the-rails-app.md
813
+ - docs/bootstrap/03-pin-the-gem.md
814
+ - docs/bootstrap/04-secrets-and-env.md
815
+ - docs/bootstrap/05-install-migrate-doctor.md
816
+ - docs/bootstrap/06-mount-and-health.md
817
+ - docs/bootstrap/07-execution-bases.md
818
+ - docs/bootstrap/08-initializer.md
819
+ - docs/bootstrap/09-rbac.md
820
+ - docs/bootstrap/10-roles-and-gates.md
821
+ - docs/bootstrap/11-auth-client-path.md
822
+ - docs/bootstrap/12-smoke-check.md
823
+ - docs/bootstrap/13-optional.md
824
+ - docs/bootstrap/14-sanity-checks.md
825
+ - docs/bootstrap/README.md
795
826
  - docs/change_password_workflow.md
796
827
  - docs/controllers.md
797
828
  - docs/cookie_authentication_guide.md
@@ -816,6 +847,8 @@ files:
816
847
  - docs/upgrades/0.14.0.md
817
848
  - docs/upgrades/0.15.0.md
818
849
  - docs/upgrades/0.16.0.md
850
+ - docs/upgrades/0.17.0.md
851
+ - docs/upgrades/0.18.0.md
819
852
  - docs/upgrades/README.md
820
853
  - lib/command_tower.rb
821
854
  - lib/command_tower/admin_scope.rb
@@ -838,6 +871,8 @@ files:
838
871
  - lib/command_tower/authorization/effective_entity_grants.rb
839
872
  - lib/command_tower/authorization/entity.rb
840
873
  - lib/command_tower/authorization/role.rb
874
+ - lib/command_tower/client_compatibility.rb
875
+ - lib/command_tower/client_compatibility/version.rb
841
876
  - lib/command_tower/configuration/account_deletion/config.rb
842
877
  - lib/command_tower/configuration/admin/config.rb
843
878
  - lib/command_tower/configuration/admin_scope/config.rb
@@ -850,6 +885,7 @@ files:
850
885
  - lib/command_tower/configuration/credentials/smtp.rb
851
886
  - lib/command_tower/configuration/credentials/twilio.rb
852
887
  - lib/command_tower/configuration/email/config.rb
888
+ - lib/command_tower/configuration/email_theme/config.rb
853
889
  - lib/command_tower/configuration/identity/config.rb
854
890
  - lib/command_tower/configuration/identity/phone_verification.rb
855
891
  - lib/command_tower/configuration/impersonation/config.rb
@@ -873,7 +909,15 @@ files:
873
909
  - lib/command_tower/configuration/registry/admin_workspace/tool_definition.rb
874
910
  - lib/command_tower/configuration/registry/audit/config.rb
875
911
  - lib/command_tower/configuration/registry/audit/event_definition.rb
912
+ - lib/command_tower/configuration/registry/client_compatibility/binding_definition.rb
913
+ - lib/command_tower/configuration/registry/client_compatibility/config.rb
914
+ - lib/command_tower/configuration/registry/client_compatibility/contract_definition.rb
915
+ - lib/command_tower/configuration/registry/client_compatibility/entity_requirement_definition.rb
916
+ - lib/command_tower/configuration/registry/client_compatibility/minimum_overrides.rb
917
+ - lib/command_tower/configuration/registry/client_compatibility/platform_definition.rb
876
918
  - lib/command_tower/configuration/registry/config.rb
919
+ - lib/command_tower/configuration/registry/inbox_presentations/config.rb
920
+ - lib/command_tower/configuration/registry/inbox_presentations/presentation_definition.rb
877
921
  - lib/command_tower/configuration/registry/principal_capabilities/capability_definition.rb
878
922
  - lib/command_tower/configuration/registry/principal_capabilities/config.rb
879
923
  - lib/command_tower/configuration/signup_session/config.rb
@@ -896,6 +940,7 @@ files:
896
940
  - lib/command_tower/impersonation/apply_overlay.rb
897
941
  - lib/command_tower/impersonation/clear_overlay_for_audit.rb
898
942
  - lib/command_tower/impersonation/establish_identity.rb
943
+ - lib/command_tower/inbox_presentations.rb
899
944
  - lib/command_tower/install/baseline.rb
900
945
  - lib/command_tower/install/doctor.rb
901
946
  - lib/command_tower/intervention/severity.rb