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
@@ -1,4 +1,6 @@
1
1
  # lib/familia/horreum/persistence.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  module Familia
4
6
  # Familia::Horreum
@@ -35,164 +37,172 @@ module Familia
35
37
  # Handles conversion between Ruby objects and Valkey hash storage
36
38
  #
37
39
  module Persistence
38
- # Persists the object to Valkey storage with automatic timestamping and validation.
40
+ # Persists object state to storage with timestamps, validation, and indexing.
39
41
  #
40
- # Saves the current object state to Valkey storage, automatically setting
41
- # created and updated timestamps if the object supports them. The method
42
- # validates unique indexes before the transaction, commits all persistent
43
- # fields, and optionally updates the key's expiration.
42
+ # Performs a complete save operation in an atomic transaction:
43
+ # - Sets created/updated timestamps
44
+ # - Validates unique index constraints
45
+ # - Persists all fields
46
+ # - Updates expiration (optional)
47
+ # - Updates class-level indexes
48
+ # - Adds to instances collection
44
49
  #
45
- # @param update_expiration [Boolean] Whether to update the key's expiration
46
- # time after saving. Defaults to true.
50
+ # ## Transaction Safety
47
51
  #
48
- # @return [Boolean] true if the save operation was successful, false otherwise.
52
+ # This method CANNOT be called within a transaction context. The save process
53
+ # requires reading current state to validate unique constraints, which would
54
+ # return uninspectable Redis::Future objects inside transactions.
49
55
  #
50
- # @raise [Familia::OperationModeError] If called within an existing transaction.
51
- # Guards need to read current values, which is not possible inside MULTI/EXEC.
52
- # @raise [Familia::RecordExistsError] If a unique index constraint is violated
53
- # for any class-level unique_index relationships.
56
+ # ### Correct Pattern:
57
+ # customer = Customer.new(email: 'test@example.com')
58
+ # customer.save # Validates unique constraints here
54
59
  #
55
- # @example Save an object to Valkey
56
- # user = User.new(name: "John", email: "john@example.com")
57
- # user.save
58
- # # => true
60
+ # customer.transaction do
61
+ # # Perform other atomic operations
62
+ # customer.increment(:login_count)
63
+ # customer.hset(:last_login, Time.now.to_i)
64
+ # end
59
65
  #
60
- # @example Save without updating expiration
61
- # user.save(update_expiration: false)
62
- # # => true
66
+ # ### Incorrect Pattern:
67
+ # Customer.transaction do
68
+ # customer = Customer.new(email: 'test@example.com')
69
+ # customer.save # Raises Familia::OperationModeError
70
+ # end
63
71
  #
64
- # @example Handle duplicate unique index
65
- # user2 = User.new(name: "Jane", email: "john@example.com")
66
- # user2.save
67
- # # => raises Familia::RecordExistsError
72
+ # @param update_expiration [Boolean] Whether to refresh key expiration (default: true)
73
+ # @return [Boolean] true on success
68
74
  #
69
- # @note Cannot be called within a transaction. Call save first to start
70
- # the transaction, or use commit_fields/hmset for manual field updates
71
- # within transactions.
75
+ # @raise [Familia::OperationModeError] If called within a transaction
76
+ # @raise [Familia::RecordExistsError] If unique index constraint violated
72
77
  #
73
- # @note When Familia.debug? is enabled, this method will trace the save
74
- # operation for debugging purposes.
78
+ # @example Basic usage
79
+ # user = User.new(email: "john@example.com")
80
+ # user.save # => true
75
81
  #
76
- # @see #commit_fields The underlying method that performs the field persistence
77
- # @see #guard_unique_indexes! Automatic validation of class-level unique indexes
82
+ # @see #save_if_not_exists! For conditional saves
83
+ # @see #transaction For atomic operations after save
78
84
  #
79
85
  def save(update_expiration: true)
86
+ start_time = Familia.now_in_μs if Familia.debug?
87
+
80
88
  # Prevent save within transaction - unique index guards require read operations
81
89
  # which are not available in Redis MULTI/EXEC blocks
82
90
  if Fiber[:familia_transaction]
83
- raise Familia::OperationModeError,
84
- "Cannot call save within a transaction. Save operations must be called outside transactions to ensure unique constraints can be validated."
91
+ raise Familia::OperationModeError, <<~ERROR_MESSAGE
92
+ Cannot call save within a transaction. Save operations must be called outside transactions to ensure unique constraints can be validated.
93
+ ERROR_MESSAGE
85
94
  end
86
95
 
87
96
  Familia.trace :SAVE, nil, self.class.uri if Familia.debug?
88
97
 
89
- # Update timestamp fields before saving
90
- self.created ||= Familia.now if respond_to?(:created)
91
- self.updated = Familia.now if respond_to?(:updated)
92
-
93
- # Validate unique indexes BEFORE the transaction
94
- guard_unique_indexes!
98
+ # Prepare object for persistence (timestamps, validation)
99
+ prepare_for_save
95
100
 
96
101
  # Everything in ONE transaction for complete atomicity
97
102
  result = transaction do |_conn|
98
- # 1. Save all fields
99
- prepared_h = to_h_for_storage
100
- hmset_result = hmset(prepared_h)
101
-
102
- # 2. Set expiration in same transaction
103
- self.update_expiration if update_expiration
104
-
105
- # 3. Update class-level indexes
106
- auto_update_class_indexes
103
+ persist_to_storage(update_expiration)
104
+ end
107
105
 
108
- # 4. Add to instances collection if available
109
- self.class.instances.add(identifier, Familia.now) if self.class.respond_to?(:instances)
106
+ # Structured lifecycle logging and instrumentation
107
+ if Familia.debug? && start_time
108
+ duration = Familia.now_in_μs - start_time
109
+
110
+ begin
111
+ fields_count = to_h_for_storage.size
112
+ rescue => e
113
+ Familia.error "Failed to serialize fields for logging",
114
+ error: e.message,
115
+ class: self.class.name,
116
+ identifier: (identifier rescue nil)
117
+ fields_count = 0
118
+ end
110
119
 
111
- hmset_result
120
+ Familia.debug "Horreum saved",
121
+ class: self.class.name,
122
+ identifier: identifier,
123
+ duration: duration,
124
+ fields_count: fields_count,
125
+ update_expiration: update_expiration
126
+
127
+ Familia::Instrumentation.notify_lifecycle(:save, self,
128
+ duration: duration,
129
+ update_expiration: update_expiration,
130
+ fields_count: fields_count
131
+ )
112
132
  end
113
133
 
114
- Familia.ld "[save] #{self.class} #{dbkey} #{result} (update_expiration: #{update_expiration})"
115
-
116
134
  # Return boolean indicating success
117
135
  !result.nil?
118
136
  end
119
137
 
120
- # Saves the object to Valkey storage only if it doesn't already exist.
121
- #
122
- # Conditionally persists the object to Valkey storage by first checking if the
123
- # identifier field already exists. If the object already exists in storage,
124
- # raises an error. Otherwise, proceeds with a normal save operation including
125
- # automatic timestamping.
126
- #
127
- # This method provides atomic conditional creation to prevent duplicate objects
128
- # from being saved when uniqueness is required based on the identifier field.
129
- #
130
- # @param update_expiration [Boolean] Whether to update the key's expiration
131
- # time after saving. Defaults to true.
132
- #
133
- # @return [Boolean] true if the save operation was successful
134
- #
135
- # @raise [Familia::RecordExistsError] If an object with the same identifier
136
- # already exists in Valkey storage
137
- #
138
- # @example Save a new user only if it doesn't exist
139
- # user = User.new(id: 123, name: "John")
140
- # user.save_if_not_exists
141
- # # => true (saved successfully)
138
+ # Conditionally persists object only if it doesn't already exist in storage.
142
139
  #
143
- # @example Attempting to save an existing object
144
- # existing_user = User.new(id: 123, name: "Jane")
145
- # existing_user.save_if_not_exists
146
- # # => raises Familia::RecordExistsError
140
+ # Uses optimistic locking (WATCH) to atomically check existence and save.
141
+ # If the object doesn't exist, performs identical operations as save.
142
+ # If it exists, raises an error with retry logic for optimistic lock failures.
147
143
  #
148
- # @example Save without updating expiration
149
- # user.save_if_not_exists(update_expiration: false)
150
- # # => true
151
- #
152
- # @note This method uses HSETNX to atomically check and set the identifier
153
- # field, ensuring race-condition-free conditional creation.
144
+ # `save_if_not_exists` doesn't call save because of the gap between checking
145
+ # existence and persisting the data. We can't check for existence inside the
146
+ # transaction because commands are queued and not executed until EXEC
147
+ # is called (if you try you get a Redis::Future object). So here we use a
148
+ # WATCH + MULTI/EXEC pattern to fail the transaction if the key is created
149
+ # (or modified in any way) to avoid silent data corruption♀︎.
150
+
151
+ # ♀︎ Additional note about WATCH + MULTI/EXEC in Valkey/Redis or any two
152
+ # step existence check in any database: although it is more cautious,
153
+ # it is not atomic. The only way to do that is if the database process
154
+ # can determine itself whether the record already exists or not. For
155
+ # Valkey/Redis, that means writing the lua to do that.
154
156
  #
155
- # @see #save The underlying save method called when the object doesn't exist
157
+ # @param update_expiration [Boolean] Whether to refresh key expiration (default: true)
158
+ # @return [Boolean] true on successful save
156
159
  #
157
- # Check if save_if_not_exists is implemented correctly. It should:
160
+ # @raise [Familia::RecordExistsError] If object already exists
161
+ # @raise [Familia::OptimisticLockError] If retries exhausted (max 3 attempts)
162
+ # @raise [Familia::OperationModeError] If called within a transaction
158
163
  #
159
- # Check if record exists
160
- # If exists, raise Familia::RecordExistsError
161
- # If not exists, save
164
+ # @example
165
+ # user = User.new(id: 123)
166
+ # user.save_if_not_exists! # => true or raises
162
167
  def save_if_not_exists!(update_expiration: true)
163
168
  # Prevent save_if_not_exists! within transaction - needs to read existence state
164
169
  if Fiber[:familia_transaction]
165
- raise Familia::OperationModeError,
166
- "Cannot call save_if_not_exists! within a transaction. This method must be called outside transactions to properly check existence."
170
+ raise Familia::OperationModeError, <<~ERROR_MESSAGE
171
+ Cannot call save_if_not_exists! within a transaction. This method
172
+ must be called outside transactions to properly check existence.
173
+ ERROR_MESSAGE
167
174
  end
168
175
 
169
176
  identifier_field = self.class.identifier_field
170
177
 
171
- Familia.ld "[save_if_not_exists]: #{self.class} #{identifier_field}=#{identifier}"
178
+ Familia.debug "[save_if_not_exists]: #{self.class} #{identifier_field}=#{identifier}"
172
179
  Familia.trace :SAVE_IF_NOT_EXISTS, nil, self.class.uri if Familia.debug?
173
180
 
181
+ # Prepare object for persistence (timestamps, validation)
182
+ prepare_for_save
183
+
174
184
  attempts = 0
175
185
  begin
176
186
  attempts += 1
177
187
 
178
- watch do
188
+ result = watch do
179
189
  raise Familia::RecordExistsError, dbkey if exists?
180
190
 
181
191
  txn_result = transaction do |_multi|
182
- hmset(to_h_for_storage)
183
-
184
- self.update_expiration if update_expiration
185
-
186
- # Auto-index for class-level indexes after successful save
187
- auto_update_class_indexes
192
+ persist_to_storage(update_expiration)
188
193
  end
189
194
 
190
- Familia.ld "[save_if_not_exists]: txn_result=#{txn_result.inspect}"
195
+ Familia.debug "[save_if_not_exists]: txn_result=#{txn_result.inspect}"
191
196
 
192
- txn_result.successful?
197
+ txn_result
193
198
  end
199
+
200
+ Familia.debug "[save_if_not_exists]: result=#{result.inspect}"
201
+
202
+ # Return boolean indicating success (consistent with save method)
203
+ !result.nil?
194
204
  rescue OptimisticLockError => e
195
- Familia.ld "[save_if_not_exists]: OptimisticLockError (#{attempts}): #{e.message}"
205
+ Familia.debug "[save_if_not_exists]: OptimisticLockError (#{attempts}): #{e.message}"
196
206
  raise if attempts >= 3
197
207
 
198
208
  sleep(0.001 * (2**attempts))
@@ -200,9 +210,13 @@ module Familia
200
210
  end
201
211
  end
202
212
 
213
+ # Non-raising variant of save_if_not_exists!
214
+ #
215
+ # @return [Boolean] true on success, false if object exists
216
+ # @raise [Familia::OptimisticLockError] If concurrency conflict persists after retries
203
217
  def save_if_not_exists(...)
204
218
  save_if_not_exists!(...)
205
- rescue RecordExistsError, OptimisticLockError
219
+ rescue RecordExistsError
206
220
  false
207
221
  end
208
222
 
@@ -233,7 +247,7 @@ module Familia
233
247
  #
234
248
  def commit_fields(update_expiration: true)
235
249
  prepared_value = to_h_for_storage
236
- Familia.ld "[commit_fields] Begin #{self.class} #{dbkey} #{prepared_value} (exp: #{update_expiration})"
250
+ Familia.debug "[commit_fields] Begin #{self.class} #{dbkey} #{prepared_value} (exp: #{update_expiration})"
237
251
 
238
252
  transaction do |_conn|
239
253
  # Set all fields atomically
@@ -367,7 +381,7 @@ module Familia
367
381
  Familia.trace :DESTROY!, dbkey, self.class.uri
368
382
 
369
383
  # Execute all deletion operations within a transaction
370
- transaction do |_conn|
384
+ result = transaction do |_conn|
371
385
  # Delete the main object key
372
386
  delete!
373
387
 
@@ -382,7 +396,20 @@ module Familia
382
396
  obj.delete!
383
397
  end
384
398
  end
399
+
400
+ # Remove from instances collection if available
401
+ self.class.instances.remove(identifier) if self.class.respond_to?(:instances)
385
402
  end
403
+
404
+ # Structured lifecycle logging and instrumentation
405
+ Familia.debug "Horreum destroyed",
406
+ class: self.class.name,
407
+ identifier: identifier,
408
+ key: dbkey
409
+
410
+ Familia::Instrumentation.notify_lifecycle(:destroy, self, key: dbkey)
411
+
412
+ result
386
413
  end
387
414
 
388
415
  # Clears all fields by setting them to nil.
@@ -433,7 +460,7 @@ module Familia
433
460
  raise Familia::KeyNotFoundError, dbkey unless dbclient.exists(dbkey)
434
461
 
435
462
  fields = hgetall
436
- Familia.ld "[refresh!] #{self.class} #{dbkey} fields:#{fields.keys}"
463
+ Familia.debug "[refresh!] #{self.class} #{dbkey} fields:#{fields.keys}"
437
464
 
438
465
  # Reset transient fields to nil for semantic clarity and ORM consistency
439
466
  # Transient fields have no authoritative source, so they should return to
@@ -489,7 +516,7 @@ module Familia
489
516
 
490
517
  # UnsortedSet the transient field back to nil
491
518
  send("#{field_type.method_name}=", nil)
492
- Familia.ld "[reset_transient_fields!] Reset #{field_name} to nil"
519
+ Familia.debug "[reset_transient_fields!] Reset #{field_name} to nil"
493
520
  end
494
521
  end
495
522
 
@@ -563,7 +590,7 @@ module Familia
563
590
  # Instance-scoped indexes must be manually populated because they need
564
591
  # the scope instance reference (e.g., employee.add_to_company_badge_index(company))
565
592
  if rel.within
566
- Familia.ld <<~LOG_MESSAGE
593
+ Familia.debug <<~LOG_MESSAGE
567
594
  [auto_update_class_indexes] Skipping #{rel.index_name} (requires scope context)
568
595
  LOG_MESSAGE
569
596
  next
@@ -574,6 +601,50 @@ module Familia
574
601
  send(add_method) if respond_to?(add_method)
575
602
  end
576
603
  end
604
+
605
+ # Prepares the object for persistence by setting timestamps and validating constraints
606
+ #
607
+ # This method is called by both save and save_if_not_exists to ensure consistent
608
+ # preparation logic. It updates created/updated timestamps and validates unique
609
+ # indexes before the transaction begins.
610
+ #
611
+ # @return [void]
612
+ #
613
+ def prepare_for_save
614
+ # Update timestamp fields before saving
615
+ self.created ||= Familia.now if respond_to?(:created)
616
+ self.updated = Familia.now if respond_to?(:updated)
617
+
618
+ # Validate unique indexes BEFORE the transaction
619
+ guard_unique_indexes!
620
+ end
621
+ private :prepare_for_save
622
+
623
+ # Persists the object's data to storage within a transaction
624
+ #
625
+ # This method contains the core persistence logic shared by both save and
626
+ # save_if_not_exists. It must be called within a transaction block.
627
+ #
628
+ # @param update_expiration [Boolean] Whether to update the key's expiration
629
+ # @return [Object] The result of the hmset operation
630
+ #
631
+ def persist_to_storage(update_expiration)
632
+ # 1. Save all fields to hashkey at once
633
+ prepared_h = to_h_for_storage
634
+ hmset_result = hmset(prepared_h)
635
+
636
+ # 2. Set expiration in same transaction
637
+ self.update_expiration if update_expiration
638
+
639
+ # 3. Update class-level indexes
640
+ auto_update_class_indexes
641
+
642
+ # 4. Add to instances collection if available
643
+ self.class.instances.add(identifier, Familia.now) if self.class.respond_to?(:instances)
644
+
645
+ hmset_result
646
+ end
647
+ private :persist_to_storage
577
648
  end
578
649
  end
579
650
  end
@@ -1,4 +1,6 @@
1
1
  # lib/familia/horreum/related_fields.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  module Familia
4
6
 
@@ -1,4 +1,6 @@
1
1
  # lib/familia/horreum/serialization.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  module Familia
4
6
  class Horreum
@@ -30,7 +32,7 @@ module Familia
30
32
  next unless field_type.loggable
31
33
 
32
34
  val = send(field_type.method_name)
33
- Familia.ld " [to_h] field: #{field} val: #{val.class}"
35
+ Familia.debug " [to_h] field: #{field} val: #{val.class}"
34
36
 
35
37
  # Use string key for external API compatibility
36
38
  # Return Ruby values, not JSON-encoded strings
@@ -63,7 +65,7 @@ module Familia
63
65
  prepared = serialize_value(val)
64
66
 
65
67
  if Familia.debug?
66
- Familia.ld " [to_h_for_storage] field: #{field} val: #{val.class} prepared: #{prepared&.class || '[nil]'}"
68
+ Familia.debug " [to_h_for_storage] field: #{field} val: #{val.class} prepared: #{prepared&.class || '[nil]'}"
67
69
  end
68
70
 
69
71
  # Use string key for database compatibility
@@ -96,7 +98,7 @@ module Familia
96
98
 
97
99
  method_name = field_type.method_name
98
100
  val = send(method_name)
99
- Familia.ld " [to_a] field: #{field} method: #{method_name} val: #{val.class}"
101
+ Familia.debug " [to_a] field: #{field} method: #{method_name} val: #{val.class}"
100
102
 
101
103
  # Return actual Ruby values, including nil to maintain array positions
102
104
  val
@@ -182,7 +184,24 @@ module Familia
182
184
  "Legacy plain string in #{context}: #{val.inspect} (#{dbkey_info})"
183
185
  end
184
186
 
185
- Familia.le(msg)
187
+ # Structured error logging with instrumentation
188
+ error_type = looks_like_json?(val) ? :corrupted_json : :legacy_string
189
+ Familia.error msg,
190
+ error_type: error_type,
191
+ field: field_name,
192
+ value_preview: val.to_s[0...50],
193
+ object_class: self.class.name,
194
+ identifier: (identifier rescue nil),
195
+ key: dbkey_info
196
+
197
+ # Notify instrumentation hooks
198
+ Familia::Instrumentation.notify_error(
199
+ StandardError.new(msg),
200
+ operation: :deserialization,
201
+ error_type: error_type,
202
+ field: field_name,
203
+ object_class: self.class.name
204
+ )
186
205
  end
187
206
 
188
207
  def looks_like_json?(val)
@@ -1,4 +1,6 @@
1
1
  # lib/familia/horreum/settings.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  module Familia
4
6
  # InstanceMethods - Module containing instance-level methods for Familia
@@ -1,5 +1,7 @@
1
1
  # lib/familia/horreum/utils.rb
2
2
  #
3
+ # frozen_string_literal: true
4
+
3
5
  module Familia
4
6
  # InstanceMethods - Module containing instance-level methods for Familia
5
7
  #
@@ -1,4 +1,6 @@
1
1
  # lib/familia/horreum.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  require_relative 'horreum/settings'
4
6
  require_relative 'horreum/connection'
@@ -186,6 +188,7 @@ module Familia
186
188
  # `Session.new({sessid: "abc123", custid: "user456"})` # legacy hash (robust)
187
189
  #
188
190
  def initialize(*args, **kwargs)
191
+ start_time = Familia.now_in_μs if Familia.debug?
189
192
  Familia.trace :INITIALIZE, nil, "Initializing #{self.class}" if Familia.debug?
190
193
  initialize_relatives
191
194
 
@@ -236,6 +239,17 @@ module Familia
236
239
  # end
237
240
  #
238
241
  init
242
+
243
+ # Structured lifecycle logging and instrumentation
244
+ if Familia.debug? && start_time
245
+ duration = Familia.now_in_μs - start_time
246
+ Familia.debug "Horreum initialized",
247
+ class: self.class.name,
248
+ duration: duration,
249
+ identifier: (identifier rescue nil)
250
+
251
+ Familia::Instrumentation.notify_lifecycle(:initialize, self, duration: duration)
252
+ end
239
253
  end
240
254
 
241
255
  # Initialization method called at the end of initialize
@@ -338,7 +352,7 @@ module Familia
338
352
  # the object with.
339
353
  # @return [Array] The list of field names that were updated.
340
354
  def naive_refresh(**fields)
341
- Familia.ld "[naive_refresh] #{self.class} #{dbkey} #{fields.keys}"
355
+ Familia.debug "[naive_refresh] #{self.class} #{dbkey} #{fields.keys}"
342
356
  initialize_with_keyword_args_deserialize_value(**fields)
343
357
  end
344
358
 
@@ -1,4 +1,6 @@
1
1
  # lib/familia/identifier_extractor.rb
2
+ #
3
+ # frozen_string_literal: true
2
4
 
3
5
  module Familia
4
6
  # IdentifierExtractor - Extracts identifiers from Familia objects for storage
@@ -27,7 +29,7 @@ module Familia
27
29
  # @return [String] The extracted identifier or class name
28
30
  # @raise [Familia::NotDistinguishableError] If value is not a Class or Familia::Base
29
31
  #
30
- def identifier_extractor(value, strict_values: true)
32
+ def identifier_extractor(value)
31
33
  case value
32
34
  when ::Symbol, ::String, ::Integer, ::Float
33
35
  Familia.trace :IDENTIFIER_EXTRACTOR, nil, 'simple_value' if Familia.debug?