familia 2.0.0.pre19 → 2.0.0.pre22

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 (370) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/claude-code-review.yml +4 -9
  3. data/.github/workflows/code-smells.yml +64 -3
  4. data/.pre-commit-config.yaml +8 -6
  5. data/.reek.yml +10 -9
  6. data/.rubocop.yml +4 -0
  7. data/.talismanrc +5 -1
  8. data/CHANGELOG.rst +220 -112
  9. data/CLAUDE.md +28 -1
  10. data/Gemfile +1 -1
  11. data/Gemfile.lock +20 -17
  12. data/bin/try +16 -0
  13. data/bin/tryouts +16 -0
  14. data/docs/1106-participates_in-bidirectional-solution.md +129 -0
  15. data/docs/guides/encryption.md +486 -0
  16. data/docs/guides/feature-encrypted-fields.md +123 -7
  17. data/docs/guides/feature-expiration.md +161 -117
  18. data/docs/guides/feature-external-identifiers.md +415 -443
  19. data/docs/guides/feature-object-identifiers.md +400 -269
  20. data/docs/guides/feature-quantization.md +120 -6
  21. data/docs/guides/feature-relationships-indexing.md +318 -0
  22. data/docs/guides/feature-relationships-methods.md +146 -604
  23. data/docs/guides/feature-relationships-participation.md +263 -0
  24. data/docs/guides/feature-relationships.md +118 -136
  25. data/docs/guides/feature-system-devs.md +176 -693
  26. data/docs/guides/feature-system.md +119 -6
  27. data/docs/guides/feature-transient-fields.md +81 -0
  28. data/docs/guides/field-system.md +778 -0
  29. data/docs/guides/index.md +32 -15
  30. data/docs/guides/logging.md +187 -0
  31. data/docs/guides/optimized-loading.md +674 -0
  32. data/docs/guides/thread-safety-monitoring.md +61 -0
  33. data/docs/guides/{time-utilities.md → time-literals.md} +12 -12
  34. data/docs/migrating/v2.0.0-pre22.md +241 -0
  35. data/docs/overview.md +7 -9
  36. data/docs/reference/api-technical.md +267 -320
  37. data/examples/autoloader/mega_customer/features/deprecated_fields.rb +2 -0
  38. data/examples/autoloader/mega_customer/safe_dump_fields.rb +2 -0
  39. data/examples/autoloader/mega_customer.rb +2 -0
  40. data/examples/datatype_standalone.rb +4 -3
  41. data/examples/encrypted_fields.rb +2 -1
  42. data/examples/json_usage_patterns.rb +2 -0
  43. data/examples/relationships.rb +3 -0
  44. data/examples/safe_dump.rb +2 -1
  45. data/examples/sampling_demo.rb +53 -0
  46. data/examples/single_connection_transaction_confusions.rb +2 -1
  47. data/familia.gemspec +2 -1
  48. data/lib/familia/base.rb +2 -0
  49. data/lib/familia/connection/behavior.rb +2 -0
  50. data/lib/familia/connection/handlers.rb +2 -0
  51. data/lib/familia/connection/individual_command_proxy.rb +2 -0
  52. data/lib/familia/connection/middleware.rb +34 -24
  53. data/lib/familia/connection/operation_core.rb +3 -2
  54. data/lib/familia/connection/operations.rb +2 -0
  55. data/lib/familia/connection/pipelined_core.rb +3 -3
  56. data/lib/familia/connection/transaction_core.rb +69 -2
  57. data/lib/familia/connection.rb +18 -3
  58. data/lib/familia/data_type/class_methods.rb +3 -1
  59. data/lib/familia/data_type/connection.rb +2 -0
  60. data/lib/familia/data_type/database_commands.rb +2 -0
  61. data/lib/familia/data_type/serialization.rb +79 -52
  62. data/lib/familia/data_type/settings.rb +2 -0
  63. data/lib/familia/data_type/types/counter.rb +2 -0
  64. data/lib/familia/data_type/types/hashkey.rb +7 -5
  65. data/lib/familia/data_type/types/listkey.rb +2 -0
  66. data/lib/familia/data_type/types/lock.rb +2 -0
  67. data/lib/familia/data_type/types/sorted_set.rb +7 -10
  68. data/lib/familia/data_type/types/stringkey.rb +24 -0
  69. data/lib/familia/data_type/types/unsorted_set.rb +2 -0
  70. data/lib/familia/data_type.rb +2 -0
  71. data/lib/familia/encryption/encrypted_data.rb +4 -2
  72. data/lib/familia/encryption/manager.rb +2 -0
  73. data/lib/familia/encryption/provider.rb +2 -0
  74. data/lib/familia/encryption/providers/aes_gcm_provider.rb +2 -0
  75. data/lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb +2 -0
  76. data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +2 -0
  77. data/lib/familia/encryption/registry.rb +2 -0
  78. data/lib/familia/encryption/request_cache.rb +2 -0
  79. data/lib/familia/encryption.rb +9 -2
  80. data/lib/familia/errors.rb +2 -0
  81. data/lib/familia/features/autoloader.rb +2 -0
  82. data/lib/familia/features/encrypted_fields/concealed_string.rb +2 -0
  83. data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +4 -0
  84. data/lib/familia/features/encrypted_fields.rb +2 -2
  85. data/lib/familia/features/expiration/extensions.rb +3 -1
  86. data/lib/familia/features/expiration.rb +12 -4
  87. data/lib/familia/features/external_identifier.rb +62 -7
  88. data/lib/familia/features/object_identifier.rb +49 -0
  89. data/lib/familia/features/quantization.rb +3 -1
  90. data/lib/familia/features/relationships/README.md +3 -1
  91. data/lib/familia/features/relationships/collection_operations.rb +2 -0
  92. data/lib/familia/features/relationships/indexing/multi_index_generators.rb +138 -9
  93. data/lib/familia/features/relationships/indexing/rebuild_strategies.rb +479 -0
  94. data/lib/familia/features/relationships/indexing/unique_index_generators.rb +97 -21
  95. data/lib/familia/features/relationships/indexing.rb +3 -0
  96. data/lib/familia/features/relationships/indexing_relationship.rb +3 -1
  97. data/lib/familia/features/relationships/participation/participant_methods.rb +131 -14
  98. data/lib/familia/features/relationships/participation/rebuild_strategies.md +41 -0
  99. data/lib/familia/features/relationships/participation/target_methods.rb +6 -6
  100. data/lib/familia/features/relationships/participation.rb +155 -69
  101. data/lib/familia/features/relationships/participation_membership.rb +69 -0
  102. data/lib/familia/features/relationships/participation_relationship.rb +34 -6
  103. data/lib/familia/features/relationships/score_encoding.rb +2 -0
  104. data/lib/familia/features/relationships.rb +5 -3
  105. data/lib/familia/features/safe_dump.rb +2 -0
  106. data/lib/familia/features/transient_fields/redacted_string.rb +2 -0
  107. data/lib/familia/features/transient_fields/single_use_redacted_string.rb +2 -0
  108. data/lib/familia/features/transient_fields/transient_field_type.rb +5 -3
  109. data/lib/familia/features/transient_fields.rb +2 -0
  110. data/lib/familia/features.rb +2 -0
  111. data/lib/familia/field_type.rb +3 -1
  112. data/lib/familia/horreum/connection.rb +17 -1
  113. data/lib/familia/horreum/database_commands.rb +8 -1
  114. data/lib/familia/horreum/definition.rb +16 -6
  115. data/lib/familia/horreum/management.rb +353 -52
  116. data/lib/familia/horreum/persistence.rb +179 -108
  117. data/lib/familia/horreum/related_fields.rb +2 -0
  118. data/lib/familia/horreum/serialization.rb +23 -4
  119. data/lib/familia/horreum/settings.rb +2 -0
  120. data/lib/familia/horreum/utils.rb +2 -0
  121. data/lib/familia/horreum.rb +15 -1
  122. data/lib/familia/identifier_extractor.rb +3 -1
  123. data/lib/familia/instrumentation.rb +156 -0
  124. data/lib/familia/json_serializer.rb +2 -0
  125. data/lib/familia/logging.rb +92 -32
  126. data/lib/familia/refinements/dear_json.rb +2 -0
  127. data/lib/familia/refinements/stylize_words.rb +2 -14
  128. data/lib/familia/refinements/time_literals.rb +2 -0
  129. data/lib/familia/refinements.rb +2 -0
  130. data/lib/familia/secure_identifier.rb +10 -2
  131. data/lib/familia/settings.rb +2 -0
  132. data/lib/familia/thread_safety/instrumented_mutex.rb +166 -0
  133. data/lib/familia/thread_safety/monitor.rb +328 -0
  134. data/lib/familia/utils.rb +13 -0
  135. data/lib/familia/verifiable_identifier.rb +3 -1
  136. data/lib/familia/version.rb +3 -1
  137. data/lib/familia.rb +31 -4
  138. data/lib/middleware/database_command_counter.rb +152 -0
  139. data/lib/middleware/database_logger.rb +295 -170
  140. data/lib/multi_result.rb +61 -31
  141. data/try/edge_cases/empty_identifiers_try.rb +2 -0
  142. data/try/edge_cases/hash_symbolization_try.rb +2 -0
  143. data/try/edge_cases/json_serialization_try.rb +2 -0
  144. data/try/edge_cases/legacy_data_detection/deserialization_edge_cases_try.rb +4 -0
  145. data/try/edge_cases/race_conditions_try.rb +4 -0
  146. data/try/edge_cases/reserved_keywords_try.rb +4 -0
  147. data/try/edge_cases/string_coercion_try.rb +2 -0
  148. data/try/edge_cases/ttl_side_effects_try.rb +4 -0
  149. data/try/features/count_any_edge_cases_try.rb +486 -0
  150. data/try/features/count_any_methods_try.rb +197 -0
  151. data/try/features/encrypted_fields/aad_protection_try.rb +4 -0
  152. data/try/features/encrypted_fields/concealed_string_core_try.rb +4 -0
  153. data/try/features/encrypted_fields/context_isolation_try.rb +4 -0
  154. data/try/features/encrypted_fields/encrypted_fields_core_try.rb +33 -0
  155. data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +4 -0
  156. data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +4 -0
  157. data/try/features/encrypted_fields/encrypted_fields_security_try.rb +4 -0
  158. data/try/features/encrypted_fields/error_conditions_try.rb +4 -0
  159. data/try/features/encrypted_fields/fresh_key_derivation_try.rb +4 -0
  160. data/try/features/encrypted_fields/fresh_key_try.rb +4 -0
  161. data/try/features/encrypted_fields/key_rotation_try.rb +4 -0
  162. data/try/features/encrypted_fields/memory_security_try.rb +4 -0
  163. data/try/features/encrypted_fields/missing_current_key_version_try.rb +4 -0
  164. data/try/features/encrypted_fields/nonce_uniqueness_try.rb +4 -0
  165. data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +4 -0
  166. data/try/features/encrypted_fields/thread_safety_try.rb +4 -0
  167. data/try/features/encrypted_fields/universal_serialization_safety_try.rb +4 -0
  168. data/try/features/encryption/config_persistence_try.rb +4 -0
  169. data/try/features/encryption/core_try.rb +4 -0
  170. data/try/features/encryption/instance_variable_scope_try.rb +4 -0
  171. data/try/features/encryption/module_loading_try.rb +4 -0
  172. data/try/features/encryption/providers/aes_gcm_provider_try.rb +4 -0
  173. data/try/features/encryption/providers/xchacha20_poly1305_provider_try.rb +4 -0
  174. data/try/features/encryption/roundtrip_validation_try.rb +4 -0
  175. data/try/features/encryption/secure_memory_handling_try.rb +4 -0
  176. data/try/features/expiration/expiration_try.rb +4 -0
  177. data/try/features/external_identifier/external_identifier_try.rb +305 -8
  178. data/try/features/feature_dependencies_try.rb +2 -0
  179. data/try/features/feature_improvements_try.rb +2 -0
  180. data/try/features/field_groups_try.rb +2 -0
  181. data/try/features/object_identifier/object_identifier_integration_try.rb +12 -9
  182. data/try/features/object_identifier/object_identifier_try.rb +140 -0
  183. data/try/features/quantization/quantization_try.rb +4 -0
  184. data/try/features/real_feature_integration_try.rb +2 -0
  185. data/try/features/relationships/indexing_commands_verification_try.rb +2 -0
  186. data/try/features/relationships/indexing_rebuild_try.rb +606 -0
  187. data/try/features/relationships/indexing_try.rb +2 -0
  188. data/try/features/relationships/participation_bidirectional_try.rb +242 -0
  189. data/try/features/relationships/participation_commands_verification_spec.rb +4 -0
  190. data/try/features/relationships/participation_commands_verification_try.rb +2 -0
  191. data/try/features/relationships/participation_performance_improvements_try.rb +11 -9
  192. data/try/features/relationships/participation_reverse_index_try.rb +15 -13
  193. data/try/features/relationships/participation_target_class_resolution_try.rb +209 -0
  194. data/try/features/relationships/participation_unresolved_target_try.rb +109 -0
  195. data/try/features/relationships/relationships_api_changes_try.rb +2 -0
  196. data/try/features/relationships/relationships_edge_cases_try.rb +4 -0
  197. data/try/features/relationships/relationships_performance_minimal_try.rb +4 -0
  198. data/try/features/relationships/relationships_performance_simple_try.rb +4 -0
  199. data/try/features/relationships/relationships_performance_try.rb +4 -0
  200. data/try/features/relationships/relationships_performance_working_try.rb +4 -0
  201. data/try/features/relationships/relationships_try.rb +6 -4
  202. data/try/features/safe_dump/safe_dump_advanced_try.rb +4 -0
  203. data/try/features/safe_dump/safe_dump_try.rb +4 -0
  204. data/try/features/transient_fields/redacted_string_try.rb +2 -0
  205. data/try/features/transient_fields/refresh_reset_try.rb +3 -0
  206. data/try/features/transient_fields/simple_refresh_test.rb +3 -0
  207. data/try/features/transient_fields/single_use_redacted_string_try.rb +2 -0
  208. data/try/features/transient_fields/transient_fields_core_try.rb +4 -0
  209. data/try/features/transient_fields/transient_fields_integration_try.rb +4 -0
  210. data/try/integration/connection/fiber_context_preservation_try.rb +4 -0
  211. data/try/integration/connection/handler_constraints_try.rb +4 -0
  212. data/try/integration/connection/isolated_dbclient_try.rb +4 -0
  213. data/try/integration/connection/middleware_reconnect_try.rb +2 -0
  214. data/try/integration/connection/operation_mode_guards_try.rb +4 -0
  215. data/try/integration/connection/pipeline_fallback_integration_try.rb +3 -0
  216. data/try/integration/connection/pools_try.rb +4 -0
  217. data/try/integration/connection/responsibility_chain_tracking_try.rb +4 -0
  218. data/try/integration/connection/transaction_fallback_integration_try.rb +4 -0
  219. data/try/integration/connection/transaction_mode_permissive_try.rb +4 -0
  220. data/try/integration/connection/transaction_mode_strict_try.rb +4 -0
  221. data/try/integration/connection/transaction_mode_warn_try.rb +4 -0
  222. data/try/integration/connection/transaction_modes_try.rb +4 -0
  223. data/try/integration/conventional_inheritance_try.rb +4 -0
  224. data/try/integration/create_method_try.rb +4 -0
  225. data/try/integration/cross_component_try.rb +4 -0
  226. data/try/integration/data_types/datatype_pipelines_try.rb +9 -3
  227. data/try/integration/data_types/datatype_transactions_try.rb +17 -7
  228. data/try/integration/database_consistency_try.rb +4 -0
  229. data/try/integration/familia_extended_try.rb +4 -0
  230. data/try/integration/familia_members_methods_try.rb +4 -0
  231. data/try/integration/models/customer_safe_dump_try.rb +4 -0
  232. data/try/integration/models/customer_try.rb +7 -3
  233. data/try/integration/models/datatype_base_try.rb +4 -0
  234. data/try/integration/models/familia_object_try.rb +4 -0
  235. data/try/integration/persistence_operations_try.rb +4 -0
  236. data/try/integration/relationships_persistence_round_trip_try.rb +17 -14
  237. data/try/integration/save_methods_consistency_try.rb +241 -0
  238. data/try/integration/scenarios_try.rb +4 -0
  239. data/try/integration/secure_identifier_try.rb +4 -0
  240. data/try/integration/transaction_safety_core_try.rb +176 -0
  241. data/try/integration/transaction_safety_workflow_try.rb +291 -0
  242. data/try/integration/verifiable_identifier_try.rb +4 -0
  243. data/try/investigation/pipeline_routing/README.md +228 -0
  244. data/try/performance/benchmarks_try.rb +4 -0
  245. data/try/performance/transaction_safety_benchmark_try.rb +238 -0
  246. data/try/support/benchmarks/deserialization_benchmark.rb +3 -1
  247. data/try/support/benchmarks/deserialization_correctness_test.rb +3 -1
  248. data/try/support/debugging/cache_behavior_tracer.rb +4 -0
  249. data/try/support/debugging/debug_aad_process.rb +3 -0
  250. data/try/support/debugging/debug_concealed_internal.rb +3 -0
  251. data/try/support/debugging/debug_concealed_reveal.rb +3 -0
  252. data/try/support/debugging/debug_context_aad.rb +3 -0
  253. data/try/support/debugging/debug_context_simple.rb +3 -0
  254. data/try/support/debugging/debug_cross_context.rb +3 -0
  255. data/try/support/debugging/debug_database_load.rb +3 -0
  256. data/try/support/debugging/debug_encrypted_json_check.rb +3 -0
  257. data/try/support/debugging/debug_encrypted_json_step_by_step.rb +3 -0
  258. data/try/support/debugging/debug_exists_lifecycle.rb +3 -0
  259. data/try/support/debugging/debug_field_decrypt.rb +3 -0
  260. data/try/support/debugging/debug_fresh_cross_context.rb +3 -0
  261. data/try/support/debugging/debug_load_path.rb +3 -0
  262. data/try/support/debugging/debug_method_definition.rb +3 -0
  263. data/try/support/debugging/debug_method_resolution.rb +3 -0
  264. data/try/support/debugging/debug_minimal.rb +3 -0
  265. data/try/support/debugging/debug_provider.rb +3 -0
  266. data/try/support/debugging/debug_secure_behavior.rb +3 -0
  267. data/try/support/debugging/debug_string_class.rb +3 -0
  268. data/try/support/debugging/debug_test.rb +3 -0
  269. data/try/support/debugging/debug_test_design.rb +3 -0
  270. data/try/support/debugging/encryption_method_tracer.rb +4 -0
  271. data/try/support/debugging/provider_diagnostics.rb +4 -0
  272. data/try/support/helpers/test_cleanup.rb +4 -0
  273. data/try/support/helpers/test_helpers.rb +5 -0
  274. data/try/support/memory/memory_basic_test.rb +4 -0
  275. data/try/support/memory/memory_detailed_test.rb +4 -0
  276. data/try/support/memory/memory_search_for_string.rb +4 -0
  277. data/try/support/memory/test_actual_redactedstring_protection.rb +4 -0
  278. data/try/support/prototypes/atomic_saves_v1_context_proxy.rb +4 -0
  279. data/try/support/prototypes/atomic_saves_v2_connection_switching.rb +4 -0
  280. data/try/support/prototypes/atomic_saves_v3_connection_pool.rb +4 -0
  281. data/try/support/prototypes/atomic_saves_v4.rb +4 -0
  282. data/try/support/prototypes/lib/atomic_saves_v2_connection_switching_helpers.rb +4 -0
  283. data/try/support/prototypes/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -0
  284. data/try/support/prototypes/pooling/configurable_stress_test.rb +4 -0
  285. data/try/support/prototypes/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -0
  286. data/try/support/prototypes/pooling/lib/connection_pool_metrics.rb +4 -0
  287. data/try/support/prototypes/pooling/lib/connection_pool_stress_test.rb +4 -0
  288. data/try/support/prototypes/pooling/lib/connection_pool_threading_models.rb +4 -0
  289. data/try/support/prototypes/pooling/lib/visualize_stress_results.rb +4 -2
  290. data/try/support/prototypes/pooling/pool_siege.rb +4 -2
  291. data/try/support/prototypes/pooling/run_stress_tests.rb +4 -2
  292. data/try/thread_safety/README.md +496 -0
  293. data/try/thread_safety/class_connection_chain_race_try.rb +265 -0
  294. data/try/thread_safety/connection_chain_race_try.rb +148 -0
  295. data/try/thread_safety/encryption_manager_cache_race_try.rb +166 -0
  296. data/try/thread_safety/feature_registry_race_try.rb +226 -0
  297. data/try/thread_safety/fiber_pipeline_isolation_try.rb +235 -0
  298. data/try/thread_safety/fiber_transaction_isolation_try.rb +208 -0
  299. data/try/thread_safety/field_registration_race_try.rb +222 -0
  300. data/try/thread_safety/logger_initialization_race_try.rb +170 -0
  301. data/try/thread_safety/middleware_registration_race_try.rb +154 -0
  302. data/try/thread_safety/module_config_race_try.rb +175 -0
  303. data/try/thread_safety/secure_identifier_cache_race_try.rb +226 -0
  304. data/try/unit/core/autoloader_try.rb +4 -0
  305. data/try/unit/core/base_enhancements_try.rb +4 -0
  306. data/try/unit/core/connection_try.rb +4 -0
  307. data/try/unit/core/errors_try.rb +4 -0
  308. data/try/unit/core/extensions_try.rb +4 -0
  309. data/try/unit/core/familia_logger_try.rb +2 -0
  310. data/try/unit/core/familia_try.rb +4 -0
  311. data/try/unit/core/middleware_sampling_try.rb +335 -0
  312. data/try/unit/core/middleware_test_helpers_bug_try.rb +58 -0
  313. data/try/unit/core/middleware_thread_safety_try.rb +245 -0
  314. data/try/unit/core/middleware_try.rb +4 -0
  315. data/try/unit/core/settings_try.rb +4 -0
  316. data/try/unit/core/time_utils_try.rb +4 -0
  317. data/try/unit/core/tools_try.rb +4 -0
  318. data/try/unit/core/utils_try.rb +37 -0
  319. data/try/unit/data_types/boolean_try.rb +39 -22
  320. data/try/unit/data_types/counter_try.rb +4 -0
  321. data/try/unit/data_types/datatype_base_try.rb +4 -0
  322. data/try/unit/data_types/hash_try.rb +6 -2
  323. data/try/unit/data_types/list_try.rb +4 -0
  324. data/try/unit/data_types/lock_try.rb +4 -0
  325. data/try/unit/data_types/serialization_try.rb +386 -0
  326. data/try/unit/data_types/sorted_set_try.rb +4 -0
  327. data/try/unit/data_types/sorted_set_zadd_options_try.rb +4 -0
  328. data/try/unit/data_types/string_try.rb +4 -0
  329. data/try/unit/data_types/unsortedset_try.rb +4 -0
  330. data/try/unit/familia_resolve_class_try.rb +116 -0
  331. data/try/unit/horreum/auto_indexing_on_save_try.rb +5 -1
  332. data/try/unit/horreum/automatic_index_validation_try.rb +2 -0
  333. data/try/unit/horreum/base_try.rb +4 -0
  334. data/try/unit/horreum/class_methods_try.rb +4 -0
  335. data/try/unit/horreum/commands_try.rb +4 -0
  336. data/try/unit/horreum/defensive_initialization_try.rb +4 -0
  337. data/try/unit/horreum/destroy_related_fields_cleanup_try.rb +6 -1
  338. data/try/unit/horreum/enhanced_conflict_handling_try.rb +4 -0
  339. data/try/unit/horreum/field_categories_try.rb +4 -0
  340. data/try/unit/horreum/field_definition_try.rb +4 -0
  341. data/try/unit/horreum/initialization_try.rb +4 -0
  342. data/try/unit/horreum/json_type_preservation_try.rb +2 -0
  343. data/try/unit/horreum/optimized_loading_try.rb +156 -0
  344. data/try/unit/horreum/relations_try.rb +4 -0
  345. data/try/unit/horreum/serialization_persistent_fields_try.rb +4 -0
  346. data/try/unit/horreum/serialization_try.rb +4 -0
  347. data/try/unit/horreum/settings_try.rb +4 -0
  348. data/try/unit/horreum/unique_index_edge_cases_try.rb +4 -0
  349. data/try/unit/horreum/unique_index_guard_validation_try.rb +2 -0
  350. data/try/unit/middleware/database_command_counter_methods_try.rb +139 -0
  351. data/try/unit/middleware/database_logger_methods_try.rb +251 -0
  352. data/try/unit/refinements/dear_json_array_methods_try.rb +4 -0
  353. data/try/unit/refinements/dear_json_hash_methods_try.rb +4 -0
  354. data/try/unit/refinements/time_literals_numeric_methods_try.rb +4 -0
  355. data/try/unit/refinements/time_literals_string_methods_try.rb +4 -0
  356. data/try/unit/thread_safety_monitor_try.rb +149 -0
  357. metadata +69 -17
  358. data/.github/workflows/code-quality.yml +0 -138
  359. data/changelog.d/20251011_012003_delano_159_datatype_transaction_pipeline_support.rst +0 -91
  360. data/changelog.d/20251011_203905_delano_next.rst +0 -30
  361. data/changelog.d/20251011_212633_delano_next.rst +0 -13
  362. data/changelog.d/20251011_221253_delano_next.rst +0 -26
  363. data/docs/archive/FAMILIA_RELATIONSHIPS.md +0 -210
  364. data/docs/archive/FAMILIA_TECHNICAL.md +0 -823
  365. data/docs/archive/FAMILIA_UPDATE.md +0 -226
  366. data/docs/archive/README.md +0 -64
  367. data/docs/archive/api-reference.md +0 -333
  368. data/docs/guides/core-field-system.md +0 -806
  369. data/docs/guides/implementation.md +0 -276
  370. data/docs/guides/security-model.md +0 -183
@@ -0,0 +1,61 @@
1
+ Thread Safety Monitoring Usage Guide
2
+
3
+ ### Development
4
+ ```ruby
5
+ # Enable monitoring during local testing
6
+ Familia.start_monitoring!
7
+ # ... run your application ...
8
+ report = Familia.thread_safety_report
9
+ puts report[:hot_spots] # See which mutexes are contentious
10
+ puts report[:recommendations] # Get actionable insights
11
+ ```
12
+
13
+ ### CI/CD
14
+ ```bash
15
+ # Add to test pipeline for race condition detection
16
+ FAMILIA_THREAD_SAFETY=1 bundle exec rspec
17
+ # Check for any race detections in CI logs
18
+ ```
19
+
20
+ ```ruby
21
+ # In test setup
22
+ if ENV['FAMILIA_THREAD_SAFETY']
23
+ Familia.start_monitoring!
24
+ at_exit do
25
+ report = Familia.thread_safety_report
26
+ if report[:summary][:race_detections] > 0
27
+ puts "❌ Race conditions detected: #{report[:summary][:race_detections]}"
28
+ exit 1
29
+ end
30
+ end
31
+ end
32
+ ```
33
+
34
+ ### Production
35
+ **APM Integration:**
36
+ ```ruby
37
+ # Export metrics to DataDog, NewRelic, etc.
38
+ Thread.new do
39
+ loop do
40
+ metrics = Familia.thread_safety_metrics
41
+ StatsD.gauge('familia.thread_safety.health_score', metrics['familia.thread_safety.health_score'])
42
+ StatsD.count('familia.thread_safety.contentions', metrics['familia.thread_safety.mutex_contentions'])
43
+ sleep 60
44
+ end
45
+ end
46
+ ```
47
+
48
+ **Health Check Endpoint:**
49
+ ```ruby
50
+ # In Rails routes or Sinatra
51
+ get '/health/thread_safety' do
52
+ report = Familia.thread_safety_report
53
+ status = report[:health] >= 80 ? 200 : 503
54
+ json report
55
+ end
56
+ ```
57
+
58
+ **Key Alerts:**
59
+ - `health_score < 70` → Investigate contention
60
+ - `race_detections > 0` → Critical issue
61
+ - `avg_wait_ms > 100` → Performance problem
@@ -9,8 +9,8 @@ The `Familia::Refinements::TimeLiterals` module extends Ruby's built-in classes
9
9
  ```ruby
10
10
  using Familia::Refinements::TimeLiterals
11
11
 
12
- 2.hours #=> 7200 (seconds)
13
- "30m".in_seconds #=> 1800
12
+ 2.hours #=> 7200.0 (seconds)
13
+ "30m".in_seconds #=> 1800.0
14
14
  timestamp.days_old #=> 5.2
15
15
  ```
16
16
 
@@ -45,12 +45,12 @@ using Familia::Refinements::TimeLiterals
45
45
  # Singular and plural forms work identically
46
46
  1.second #=> 1
47
47
  30.seconds #=> 30
48
- 5.minutes #=> 300
49
- 2.hours #=> 7200
50
- 3.days #=> 259200
51
- 1.week #=> 604800
52
- 2.months #=> 5259492
53
- 1.year #=> 31556952
48
+ 5.minutes #=> 300.0
49
+ 2.hours #=> 7200.0
50
+ 3.days #=> 259200.0
51
+ 1.week #=> 604800.0
52
+ 2.months #=> 5259492.0
53
+ 1.year #=> 31556952.0
54
54
  ```
55
55
 
56
56
  ### Converting Time Units Back
@@ -80,9 +80,9 @@ Parse human-readable time strings:
80
80
 
81
81
  | Unit | Abbreviations | Example |
82
82
  |------|---------------|---------|
83
- | Microseconds | `us`, `μs`, `microsecond`, `microseconds` | `"500us"` |
83
+ | Microseconds | `us`, `μs`, `microsecond`, `microseconds` | `"500μs"` |
84
84
  | Milliseconds | `ms`, `millisecond`, `milliseconds` | `"250ms"` |
85
- | Seconds | `s`, `second`, `seconds` | `"30s"` |
85
+ | Seconds | (no unit) | `"30"` |
86
86
  | Minutes | `m`, `minute`, `minutes` | `"15m"` |
87
87
  | Hours | `h`, `hour`, `hours` | `"2h"` |
88
88
  | Days | `d`, `day`, `days` | `"7d"` |
@@ -90,7 +90,7 @@ Parse human-readable time strings:
90
90
  | Months | `mo`, `month`, `months` | `"6mo"` |
91
91
  | Years | `y`, `year`, `years` | `"1y"` |
92
92
 
93
- **Note**: Use `"mo"` for months to avoid confusion with `"m"` (minutes).
93
+ **Note**: Use `"mo"` for months to avoid confusion with `"m"` (minutes). Seconds don't require a unit suffix.
94
94
 
95
95
  ## Age Calculations
96
96
 
@@ -215,7 +215,7 @@ If upgrading from earlier versions:
215
215
  12.months != 1.year # Different values
216
216
 
217
217
  # New behavior (consistent)
218
- 12.months == 1.year # Same value: 31,556,952 seconds
218
+ 12.months == 1.year # Same value: 31,556,952.0 seconds
219
219
  ```
220
220
 
221
221
  Update any code that relied on the old 365-day year constant to expect the new Gregorian year values.
@@ -0,0 +1,241 @@
1
+ # Migrating Guide: v2.0.0-pre22
2
+
3
+ This version introduces significant performance optimizations for Redis operations, completes the bidirectional relationships feature, and improves flexibility for external identifiers.
4
+
5
+ ## Major Features
6
+
7
+ ### Bidirectional Relationship Methods
8
+
9
+ **What's New:**
10
+
11
+ The `participates_in` declarations now generate reverse collection methods with the `_instances` suffix, providing symmetric access to relationships from both directions.
12
+
13
+ **Generated Methods:**
14
+ ```ruby
15
+ class User < Familia::Horreum
16
+ participates_in Team, :members
17
+ participates_in Organization, :employees
18
+ end
19
+
20
+ # New reverse collection methods:
21
+ user.team_instances # => [team1, team2]
22
+ user.team_ids # => ["team_123", "team_456"]
23
+ user.team? # => true/false
24
+ user.team_count # => 2
25
+
26
+ user.organization_instances # => [org1]
27
+ user.organization_ids # => ["org_789"]
28
+ ```
29
+
30
+ **Custom Names:**
31
+ ```ruby
32
+ class User < Familia::Horreum
33
+ participates_in Organization, :contractors, as: :clients
34
+ end
35
+
36
+ user.clients_instances # Instead of organization_instances
37
+ user.clients_ids # Instead of organization_ids
38
+ ```
39
+
40
+ **Migration:**
41
+
42
+ No changes required for existing code. The new methods are additive and don't affect existing `participates_in` functionality.
43
+
44
+ ### Pipelined Bulk Loading
45
+
46
+ **What's New:**
47
+
48
+ New `load_multi` methods provide up to 2× performance improvement for bulk object loading by using Redis pipelining.
49
+
50
+ **Before (N×2 commands):**
51
+ ```ruby
52
+ users = ids.map { |id| User.find_by_id(id) }
53
+ # For 14 objects: 28 Redis commands (14 EXISTS + 14 HGETALL)
54
+ ```
55
+
56
+ **After (1 round trip):**
57
+ ```ruby
58
+ users = User.load_multi(ids)
59
+ # For 14 objects: 1 pipelined batch with 14 HGETALL commands
60
+ ```
61
+
62
+ **Additional Methods:**
63
+ ```ruby
64
+ # Load by full dbkeys
65
+ users = User.load_multi_by_keys(['user:123:object', 'user:456:object'])
66
+
67
+ # Filter out nils for missing objects
68
+ existing_only = User.load_multi(ids).compact
69
+ ```
70
+
71
+ ### Optional EXISTS Check Optimization
72
+
73
+ **What's New:**
74
+
75
+ The `find_by_id` and related methods now support skipping the EXISTS check for 50% reduction in Redis commands.
76
+
77
+ ```ruby
78
+ # Default behavior (unchanged, 2 commands)
79
+ user = User.find_by_id(123)
80
+
81
+ # Optimized mode (1 command)
82
+ user = User.find_by_id(123, check_exists: false)
83
+ ```
84
+
85
+ **When to Use:**
86
+ - Performance-critical paths
87
+ - Bulk operations with known-to-exist keys
88
+ - High-throughput APIs
89
+ - Loading from sorted set results
90
+
91
+ ## Enhanced Features
92
+
93
+ ### Flexible External Identifier Format
94
+
95
+ **What's New:**
96
+
97
+ The `external_identifier` feature now supports custom format templates.
98
+
99
+ **Examples:**
100
+ ```ruby
101
+ # Default format (unchanged)
102
+ class User < Familia::Horreum
103
+ feature :external_identifier
104
+ end
105
+ user.extid # => "ext_abc123def456"
106
+
107
+ # Custom prefix
108
+ class Customer < Familia::Horreum
109
+ feature :external_identifier, format: 'cust_%{id}'
110
+ end
111
+ customer.extid # => "cust_abc123def456"
112
+
113
+ # Different separator
114
+ class APIKey < Familia::Horreum
115
+ feature :external_identifier, format: 'api-%{id}'
116
+ end
117
+ key.extid # => "api-abc123def456"
118
+ ```
119
+
120
+ ### Atomic Index Rebuilding
121
+
122
+ **What's New:**
123
+
124
+ Auto-generated rebuild methods for all unique and multi indexes with zero downtime.
125
+
126
+ **Examples:**
127
+
128
+ ```ruby
129
+ # Class-level unique index
130
+ User.rebuild_email_lookup
131
+
132
+ # Instance-scoped unique index
133
+ company.rebuild_badge_index
134
+
135
+ # With progress tracking
136
+ User.rebuild_email_lookup(batch_size: 100) do |progress|
137
+ puts "#{progress[:completed]}/#{progress[:total]}"
138
+ end
139
+ ```
140
+
141
+ When to Use:
142
+ - After data migrations or bulk imports
143
+ - Recovering from index corruption
144
+ - Adding indexes to existing data
145
+
146
+ Migration:
147
+
148
+ Run rebuild methods once after upgrade to ensure index consistency. No code changes required—methods are auto-generated from existing
149
+ unique_index and multi_index declarations.
150
+
151
+
152
+ ## Bug Fixes
153
+
154
+ ### Symbol/String Target Classes in participates_in
155
+
156
+ **What Was Fixed:**
157
+
158
+ Fixed multiple bugs when using Symbol or String class names in `participates_in`:
159
+
160
+ ```ruby
161
+ class Domain < Familia::Horreum
162
+ # All forms now work correctly:
163
+ participates_in Customer, :domains # Class object
164
+ participates_in :Customer, :domains # Symbol (was broken)
165
+ participates_in 'Customer', :domains # String (was broken)
166
+ end
167
+ ```
168
+
169
+ **Errors Fixed:**
170
+ - `NoMethodError: private method 'member_by_config_name'`
171
+ - `NoMethodError: undefined method 'familia_name' for Symbol`
172
+ - `NoMethodError: undefined method 'config_name' for Symbol`
173
+ - Confusing nil errors for unloaded classes
174
+
175
+ **New Behavior:**
176
+
177
+ When a target class can't be resolved, you now get a helpful error:
178
+ ```
179
+ Target class 'Customer' could not be resolved.
180
+ Possible causes:
181
+ 1. The class hasn't been loaded yet (load order issue)
182
+ 2. The class name is misspelled
183
+ 3. The class doesn't inherit from Familia::Horreum
184
+
185
+ Registered Familia classes: ["User", "Team", "Organization"]
186
+ ```
187
+
188
+ ## Performance Recommendations
189
+
190
+ ### Use Bulk Loading for Collections
191
+
192
+ ```ruby
193
+ # ❌ Avoid N+1 queries
194
+ team.members.to_a.map { |id| User.find_by_id(id) }
195
+
196
+ # ✅ Use bulk loading
197
+ User.load_multi(team.members.to_a)
198
+ ```
199
+
200
+ ### Skip EXISTS Checks When Safe
201
+
202
+ ```ruby
203
+ # When loading from sorted sets (keys guaranteed to exist)
204
+ task_ids = project.tasks.range(0, 9)
205
+ tasks = Task.load_multi(task_ids) # Or use check_exists: false
206
+
207
+ # For known-existing keys
208
+ user = User.find_by_id(session[:user_id], check_exists: false)
209
+ ```
210
+
211
+ ### Leverage Reverse Collection Methods
212
+
213
+ ```ruby
214
+ # ❌ Manual parsing of participations
215
+ team_keys = user.participations.members.select { |k| k.start_with?("team:") }
216
+ team_ids = team_keys.map { |k| k.split(':')[1] }
217
+ teams = Team.load_multi(team_ids)
218
+
219
+ # ✅ Use generated methods
220
+ teams = user.team_instances
221
+ ```
222
+
223
+ ## Backwards Compatibility
224
+
225
+ All changes in this version are backwards compatible:
226
+
227
+ - New methods are additive and don't affect existing APIs
228
+ - Default behaviors remain unchanged
229
+ - Symbol/String fixes don't require code changes
230
+
231
+ ## Recommended Actions
232
+
233
+ 1. **Adopt bulk loading** for performance-critical paths
234
+ 2. **Use reverse collection methods** to simplify relationship queries
235
+ 3. **Consider check_exists: false** for guaranteed-existing keys
236
+ 4. **Update external_identifier formats** if custom prefixes are needed
237
+
238
+ ## See Also
239
+
240
+ - [Relationships Guide](../guides/feature-relationships.md)
241
+ - [Performance Optimization Guide](../guides/optimized-loading.md)
data/docs/overview.md CHANGED
@@ -289,13 +289,11 @@ class SecureModel < Familia::Horreum
289
289
  # → password, password= (no fast writer method)
290
290
  # → Values wrapped in RedactedString
291
291
 
292
- # Redacted fields are persisted but return [REDACTED] in logs
293
- redacted_field :security_question
294
- # → security_question, security_question=, security_question!
292
+ # Note: All transient field values are automatically wrapped in RedactedString
293
+ # for security - they never persist to the database
295
294
 
296
- # Object identifier fields auto-generate unique IDs
295
+ # Object identifier fields auto-generate unique IDs when using the feature
297
296
  # → objid, objid= (lazy generation, preserves initialization values)
298
- # → objid_generator_used (provenance tracking)
299
297
  end
300
298
 
301
299
  # Usage examples
@@ -856,7 +854,7 @@ Familia.debug = true # Shows feature loading sequence
856
854
  Familia.debug = true
857
855
 
858
856
  # Check what's in Valkey
859
- Familia.redis.keys('*') # List all keys (use carefully in production)
857
+ Familia.dbclient.keys('*') # List all keys (use carefully in production)
860
858
  ```
861
859
 
862
860
  ## Testing
@@ -880,7 +878,7 @@ Familia.config.current_key_version = :v1
880
878
 
881
879
  # Clear data between tests
882
880
  def clear_redis
883
- Familia.redis.flushdb
881
+ Familia.dbclient.flushdb
884
882
  end
885
883
 
886
884
  # Feature-specific testing patterns
@@ -898,8 +896,8 @@ end
898
896
 
899
897
  def test_relationships_cleanup
900
898
  # Clean up relationship indexes
901
- Familia.redis.keys('*:relationships:*').each do |key|
902
- Familia.redis.del(key)
899
+ Familia.dbclient.keys('*:relationships:*').each do |key|
900
+ Familia.dbclient.del(key)
903
901
  end
904
902
  end
905
903
  ```