familia 2.11.1 → 2.12.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/.github/workflows/claude-code-review.yml +14 -8
- data/.github/workflows/claude.yml +9 -25
- data/.github/workflows/code-smells.yml +1 -1
- data/.github/workflows/release-gem.yml +1 -1
- data/.github/workflows/ruby-lint.yml +1 -1
- data/.github/workflows/yardoc.yml +1 -1
- data/.gitignore +8 -2
- data/.talismanrc +13 -0
- data/AGENTS.md +7 -0
- data/CHANGELOG.rst +125 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +13 -16
- data/README.md +14 -3
- data/changelog.d/README.md +46 -54
- data/changelog.d/fragments/20260725_202500_delano_282_unsaved_index_guard.md +7 -0
- data/changelog.d/fragments/20260725_213000_delano_282_index_scope_tracker.md +18 -0
- data/changelog.d/fragments/20260728_120000_delano_365_stale_tracker_prune.rst +30 -0
- data/docs/adr/0001-record-architecture-decisions.md +20 -0
- data/docs/adr/0002-watch-for-private-keys-lua-for-shared-keys.md +62 -0
- data/docs/adr/README.md +14 -0
- data/docs/guides/datatype-collections.md +101 -1
- data/docs/guides/encryption.md +42 -7
- data/docs/guides/feature-encrypted-fields.md +2 -0
- data/docs/guides/feature-housekeeping.md +50 -1
- data/docs/guides/feature-relationships-indexing.md +241 -3
- data/docs/guides/feature-relationships-participation.md +14 -0
- data/docs/guides/index.md +10 -7
- data/docs/investigation/memory-audit.md +5 -0
- data/docs/migrating/v2.10.md +14 -0
- data/docs/overview.md +120 -37
- data/docs/reference/api-technical.md +74 -20
- data/docs/schema-validation.md +199 -0
- data/docs/security/2026-07-19-audit.md +96 -0
- data/docs/security/2026-07-30-audit.md +33 -0
- data/docs/transaction_safety.md +215 -0
- data/examples/encryption_upgrade_proof/README.md +8 -5
- data/examples/encryption_upgrade_proof/gemfiles/Gemfile.dev-no-libsodium +1 -0
- data/examples/encryption_upgrade_proof/gemfiles/Gemfile.dev-with-libsodium +1 -0
- data/examples/encryption_upgrade_proof/gemfiles/Gemfile.production-today +1 -0
- data/examples/encryption_upgrade_proof/phase2_libsodium_enabled.rb +22 -7
- data/examples/encryption_upgrade_proof/phase3_rollback_hazard.rb +1 -1
- data/familia.gemspec +0 -2
- data/lib/familia/connection/middleware.rb +4 -2
- data/lib/familia/connection/operations.rb +18 -2
- data/lib/familia/connection/transaction_core.rb +1 -1
- data/lib/familia/connection.rb +49 -3
- data/lib/familia/data_type/collection_base.rb +55 -7
- data/lib/familia/data_type/types/hashkey.rb +150 -0
- data/lib/familia/data_type/types/listkey.rb +89 -18
- data/lib/familia/data_type/types/lock.rb +34 -6
- data/lib/familia/data_type/types/sorted_set.rb +87 -22
- data/lib/familia/data_type.rb +117 -8
- data/lib/familia/encryption/manager.rb +128 -73
- data/lib/familia/encryption/provider.rb +7 -0
- data/lib/familia/encryption/providers/aes_gcm_provider.rb +3 -2
- data/lib/familia/encryption/providers/blake2b_personalization.rb +101 -0
- data/lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb +24 -13
- data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +21 -12
- data/lib/familia/errors.rb +38 -1
- data/lib/familia/features/encrypted_fields/concealed_string.rb +14 -15
- data/lib/familia/features/encrypted_fields.rb +5 -3
- data/lib/familia/features/housekeeping/enforce_collection_caps.rb +94 -0
- data/lib/familia/features/housekeeping.rb +20 -9
- data/lib/familia/features/relationships/collection_operations.rb +87 -6
- data/lib/familia/features/relationships/indexing/multi_index_generators.rb +49 -8
- data/lib/familia/features/relationships/indexing/unique_index_generators.rb +222 -33
- data/lib/familia/features/relationships/indexing.rb +483 -15
- data/lib/familia/features/relationships/participation/target_methods.rb +194 -21
- data/lib/familia/features/relationships/participation.rb +17 -5
- data/lib/familia/features/relationships/participation_relationship.rb +1 -0
- data/lib/familia/features/relationships/score_encoding.rb +109 -28
- data/lib/familia/features/relationships.rb +22 -40
- data/lib/familia/features/transient_fields/single_use_redacted_string.rb +9 -3
- data/lib/familia/features/transient_fields.rb +1 -0
- data/lib/familia/field_type.rb +206 -11
- data/lib/familia/horreum/atomic_write.rb +17 -0
- data/lib/familia/horreum/database_commands.rb +28 -4
- data/lib/familia/horreum/definition.rb +0 -111
- data/lib/familia/horreum/management/repair.rb +0 -39
- data/lib/familia/horreum/persistence.rb +988 -103
- data/lib/familia/horreum/serialization.rb +16 -2
- data/lib/familia/multi_result.rb +115 -21
- data/lib/familia/settings.rb +47 -14
- data/lib/familia/version.rb +1 -1
- data/lib/middleware/database_logger.rb +54 -7
- data/try/bug_fixes/overview_permission_example_try.rb +62 -0
- data/try/bug_fixes/partial_write_index_maintenance_try.rb +492 -0
- data/try/bug_fixes/permission_query_try.rb +151 -0
- data/try/bug_fixes/relationships_rdoc_example_try.rb +83 -0
- data/try/bug_fixes/stale_unique_index_try.rb +124 -0
- data/try/edge_cases/fast_writer_transaction_guard_try.rb +2 -4
- data/try/features/atomic_write_coverage_try.rb +2 -4
- data/try/features/dirty_tracking_try.rb +2 -4
- data/try/features/dirty_write_new_object_try.rb +22 -1
- data/try/features/dirty_write_warnings_try.rb +2 -1
- data/try/features/encrypted_fields/aad_nil_fields_try.rb +4 -6
- data/try/features/encrypted_fields/aad_protection_try.rb +4 -6
- data/try/features/encrypted_fields/aad_roundtrip_try.rb +4 -6
- data/try/features/encrypted_fields/aad_transient_fix_try.rb +4 -6
- data/try/features/encrypted_fields/aad_transient_proof_try.rb +4 -6
- data/try/features/encrypted_fields/concealed_string_core_try.rb +8 -6
- data/try/features/encrypted_fields/context_isolation_try.rb +2 -4
- data/try/features/encrypted_fields/encrypted_data_try.rb +2 -4
- data/try/features/encrypted_fields/encrypted_fields_core_try.rb +42 -1
- data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +17 -0
- data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +2 -4
- data/try/features/encrypted_fields/encrypted_fields_security_try.rb +6 -0
- data/try/features/encrypted_fields/envelope_version_branching_try.rb +4 -6
- data/try/features/encrypted_fields/envelope_version_try.rb +4 -6
- data/try/features/encrypted_fields/error_conditions_try.rb +2 -4
- data/try/features/encrypted_fields/fast_writer_try.rb +4 -6
- data/try/features/encrypted_fields/fresh_key_derivation_try.rb +2 -4
- data/try/features/encrypted_fields/fresh_key_try.rb +4 -2
- data/try/features/encrypted_fields/key_material_try.rb +4 -6
- data/try/features/encrypted_fields/key_rotation_try.rb +6 -7
- data/try/features/encrypted_fields/memory_security_try.rb +5 -5
- data/try/features/encrypted_fields/nonce_uniqueness_try.rb +2 -4
- data/try/features/encrypted_fields/per_field_algorithm_try.rb +5 -2
- data/try/features/encrypted_fields/re_encrypt_fields_try.rb +18 -26
- data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +5 -5
- data/try/features/encrypted_fields/thread_safety_try.rb +2 -4
- data/try/features/encrypted_fields/universal_serialization_safety_try.rb +5 -5
- data/try/features/encryption/aes_gcm_salt_rotation_try.rb +24 -5
- data/try/features/encryption/algorithm_upgrade_try.rb +7 -7
- data/try/features/encryption/config_persistence_try.rb +42 -5
- data/try/features/encryption/core_try.rb +4 -1
- data/try/features/encryption/encoding_phase1_try.rb +4 -1
- data/try/features/encryption/encoding_phase2_try.rb +4 -1
- data/try/features/encryption/instance_variable_scope_try.rb +5 -4
- data/try/features/encryption/module_loading_try.rb +7 -5
- data/try/features/encryption/providers/xchacha20_poly1305_provider_try.rb +51 -3
- data/try/features/encryption/request_cache_try.rb +4 -7
- data/try/features/encryption/roundtrip_validation_try.rb +3 -0
- data/try/features/encryption/secure_memory_handling_try.rb +76 -5
- data/try/features/encryption/xchacha20_personalization_rotation_try.rb +230 -0
- data/try/features/housekeeping/enforce_collection_caps_try.rb +136 -0
- data/try/features/housekeeping/housekeeping_try.rb +2 -2
- data/try/features/instance_registry_try.rb +6 -14
- data/try/features/real_feature_integration_try.rb +8 -0
- data/try/features/relationships/class_level_multi_index_try.rb +30 -0
- data/try/features/relationships/indexing_commands_verification_try.rb +19 -0
- data/try/features/relationships/relationships_edge_cases_try.rb +3 -5
- data/try/features/relationships/score_encoding_permissions_try.rb +245 -0
- data/try/features/relationships/unique_index_cas_try.rb +546 -0
- data/try/features/transient_fields/refresh_reset_try.rb +4 -1
- data/try/features/transient_fields/single_use_redacted_string_try.rb +34 -0
- data/try/integration/connection/isolated_dbclient_try.rb +34 -22
- data/try/integration/connection/middleware_reconnect_try.rb +3 -3
- data/try/integration/connection/pools_try.rb +22 -13
- data/try/integration/database_consistency_try.rb +4 -3
- data/try/integration/nil_field_absence_try.rb +160 -0
- data/try/integration/persistence_operations_try.rb +2 -4
- data/try/integration/save_methods_consistency_try.rb +52 -6
- data/try/investigation/pipeline_routing/CONCLUSION.md +149 -0
- data/try/investigation/pipeline_routing/FINDINGS.md +168 -0
- data/try/{features/transient_fields → support/debugging}/simple_refresh_test.rb +2 -2
- data/try/support/encryption_config_helper_try.rb +114 -0
- data/try/support/helpers/encryption_config.rb +169 -0
- data/try/support/helpers/test_helpers.rb +47 -0
- data/try/support/prototypes/pooling/docs/README_advanced_usage.md +636 -0
- data/try/support/prototypes/pooling/docs/README_stress_testing.md +200 -0
- data/try/thread_safety/encryption_manager_cache_race_try.rb +2 -4
- data/try/unit/core/suite_hygiene_try.rb +32 -0
- data/try/unit/core/tools_try.rb +4 -2
- data/try/unit/data_types/enumerable_consistency/large_scale_consistency_try.rb +14 -3
- data/try/unit/data_types/lock_try.rb +44 -3
- data/try/unit/data_types/max_length_try.rb +607 -0
- data/try/unit/horreum/automatic_index_validation_try.rb +89 -2
- data/try/unit/horreum/commands_try.rb +85 -0
- data/try/unit/horreum/destroy_index_cleanup_try.rb +714 -22
- data/try/unit/horreum/multi_field_update_try.rb +154 -1
- data/try/unit/horreum/serialization_try.rb +7 -4
- data/try/unit/horreum/unique_index_edge_cases_try.rb +46 -7
- data/try/unit/horreum/unique_index_guard_validation_try.rb +2 -0
- data/try/unit/middleware/database_logger_methods_try.rb +39 -0
- data/try/unit/multi_result_try.rb +298 -0
- data/try/unit/thread_safety_monitor_try.rb +20 -12
- metadata +31 -30
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d860c29966392e82cf54d842d457353d6a7268c3bf5378e25af9cb850f59d37c
|
|
4
|
+
data.tar.gz: 87fc36560a6cd68ffb614ef6b3ab11625300ebed8433508739f1ab4633f5b9ff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 15b5c9028503566db28d179052982d3a38617463753ea360f22ea49eeb86d3fc896352f18c73a703fe62d3fd5a6cdcf65f254dab284a7671f3b9a0b9db413acb
|
|
7
|
+
data.tar.gz: 633e8ae2bab11aaf362791f23f68ea7f0287e1388c38850200809c5b43ed79ae59039492258927023ea91821d39243a18c9eaa5a63d8c068fb011edc99120468
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -53,7 +53,7 @@ jobs:
|
|
|
53
53
|
bundler-cache: true
|
|
54
54
|
|
|
55
55
|
- name: Setup tmate session
|
|
56
|
-
uses: mxschmitt/action-tmate@
|
|
56
|
+
uses: mxschmitt/action-tmate@35b54afac29c97fb54faba5b513f8fbd1882f113 # v3
|
|
57
57
|
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
|
|
58
58
|
with:
|
|
59
59
|
detached: true
|
|
@@ -48,7 +48,7 @@ jobs:
|
|
|
48
48
|
|
|
49
49
|
- name: Run Claude Code Review
|
|
50
50
|
id: claude-review
|
|
51
|
-
uses: anthropics/claude-code-action@
|
|
51
|
+
uses: anthropics/claude-code-action@be7b93b1907a4abad570368f3c74b6fe3807510b # v1.0.183
|
|
52
52
|
with:
|
|
53
53
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
54
54
|
|
|
@@ -56,13 +56,23 @@ jobs:
|
|
|
56
56
|
# runs) -> the CLAUDE_MODEL repo variable -> this built-in default.
|
|
57
57
|
# Pinning a current id avoids the action's frozen default, which 404s
|
|
58
58
|
# ("model: claude-sonnet-4-20250514"). Fall back to Sonnet on overload.
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
# v1 of the action dropped the model/fallback_model/allowed_tools
|
|
60
|
+
# inputs; they are CLI flags passed via claude_args now (see
|
|
61
|
+
# docs/migration-guide.md and docs/usage.md in the action repo).
|
|
62
|
+
claude_args: |
|
|
63
|
+
--model ${{ inputs.model || vars.CLAUDE_MODEL || 'claude-opus-4-6' }}
|
|
64
|
+
--fallback-model ${{ vars.CLAUDE_FALLBACK_MODEL || 'claude-sonnet-4-6' }}
|
|
65
|
+
--allowedTools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"
|
|
61
66
|
|
|
62
67
|
# Optional: Use sticky comments to make Claude reuse the same comment on subsequent pushes to the same PR
|
|
63
68
|
use_sticky_comment: true
|
|
64
69
|
|
|
65
|
-
direct_prompt
|
|
70
|
+
# v1 renamed direct_prompt -> prompt. The REPO/PR NUMBER header is the
|
|
71
|
+
# format the migration guide calls for so Claude reviews the right PR.
|
|
72
|
+
prompt: |
|
|
73
|
+
REPO: ${{ github.repository }}
|
|
74
|
+
PR NUMBER: ${{ github.event.pull_request.number }}
|
|
75
|
+
|
|
66
76
|
Please review this pull request and provide feedback on:
|
|
67
77
|
- Code quality and best practices
|
|
68
78
|
- Potential bugs or issues
|
|
@@ -73,7 +83,3 @@ jobs:
|
|
|
73
83
|
Use the repository's AGENTS.md for guidance on style and conventions. Be constructive and helpful in your feedback.
|
|
74
84
|
|
|
75
85
|
Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR.
|
|
76
|
-
|
|
77
|
-
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
78
|
-
# or https://docs.anthropic.com/en/docs/claude-code/sdk#command-line for available options
|
|
79
|
-
allowed_tools: "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"
|
|
@@ -32,47 +32,31 @@ jobs:
|
|
|
32
32
|
|
|
33
33
|
- name: Run Claude Code
|
|
34
34
|
id: claude
|
|
35
|
-
uses: anthropics/claude-code-action@
|
|
35
|
+
uses: anthropics/claude-code-action@be7b93b1907a4abad570368f3c74b6fe3807510b # v1.0.183
|
|
36
36
|
with:
|
|
37
37
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
38
38
|
|
|
39
39
|
# Primary model: set the CLAUDE_MODEL repo variable to override without
|
|
40
40
|
# editing this file. Pinning a current id avoids the action's frozen
|
|
41
41
|
# default, which 404s ("model: claude-sonnet-4-20250514"). Fall back to
|
|
42
|
-
# Sonnet if the primary is unavailable or overloaded.
|
|
43
|
-
model
|
|
44
|
-
|
|
42
|
+
# Sonnet if the primary is unavailable or overloaded. v1 of the action
|
|
43
|
+
# dropped the model/fallback_model inputs; models are CLI flags passed
|
|
44
|
+
# via claude_args (see docs/migration-guide.md in the action repo).
|
|
45
|
+
# Other supported flags (--allowedTools, --max-turns, ...):
|
|
46
|
+
# https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
47
|
+
claude_args: |
|
|
48
|
+
--model ${{ vars.CLAUDE_MODEL || 'claude-opus-4-6' }}
|
|
49
|
+
--fallback-model ${{ vars.CLAUDE_FALLBACK_MODEL || 'claude-sonnet-4-6' }}
|
|
45
50
|
|
|
46
51
|
# This is an optional setting that allows Claude to read CI results on PRs
|
|
47
52
|
additional_permissions: |
|
|
48
53
|
actions: read
|
|
49
54
|
|
|
50
|
-
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
|
|
51
|
-
# model: "claude-opus-4-20250514"
|
|
52
|
-
|
|
53
55
|
# Optional: Customize the trigger phrase (default: @claude)
|
|
54
56
|
# trigger_phrase: "/claude"
|
|
55
57
|
|
|
56
58
|
# Optional: Trigger when specific user is assigned to an issue
|
|
57
59
|
# assignee_trigger: "claude-bot"
|
|
58
60
|
|
|
59
|
-
# Optional: Allow Claude to run specific commands
|
|
60
|
-
# allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
|
|
61
|
-
|
|
62
|
-
# Optional: Add custom instructions for Claude to customize its behavior for your project
|
|
63
|
-
# custom_instructions: |
|
|
64
|
-
# Follow our coding standards
|
|
65
|
-
# Ensure all new code has tests
|
|
66
|
-
# Use TypeScript for new files
|
|
67
|
-
|
|
68
|
-
# Optional: Custom environment variables for Claude
|
|
69
|
-
# claude_env: |
|
|
70
|
-
# NODE_ENV: test
|
|
71
|
-
|
|
72
61
|
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
|
73
62
|
# prompt: 'Update the pull request description to include a summary of changes.'
|
|
74
|
-
|
|
75
|
-
# Optional: Add claude_args to customize behavior and configuration
|
|
76
|
-
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
77
|
-
# or https://docs.anthropic.com/en/docs/claude-code/sdk#command-line for available options
|
|
78
|
-
# claude_args: '--model claude-opus-4-1-20250805 --allowed-tools Bash(gh pr:*)'
|
|
@@ -158,4 +158,4 @@ jobs:
|
|
|
158
158
|
echo "Releasing familia ${gem_version} from tag ${RELEASE_TAG}"
|
|
159
159
|
|
|
160
160
|
- name: Build and push gem to RubyGems
|
|
161
|
-
uses: rubygems/release-gem@
|
|
161
|
+
uses: rubygems/release-gem@052cc82692552de3ef2b81fd670e41d13cba8092 # v1.4.0
|
|
@@ -49,7 +49,7 @@ jobs:
|
|
|
49
49
|
bundler-cache: true
|
|
50
50
|
|
|
51
51
|
- name: Setup tmate session
|
|
52
|
-
uses: mxschmitt/action-tmate@
|
|
52
|
+
uses: mxschmitt/action-tmate@35b54afac29c97fb54faba5b513f8fbd1882f113 # v3
|
|
53
53
|
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
|
|
54
54
|
with:
|
|
55
55
|
detached: true
|
data/.gitignore
CHANGED
|
@@ -24,8 +24,14 @@ vendor
|
|
|
24
24
|
*.gem
|
|
25
25
|
public/
|
|
26
26
|
|
|
27
|
-
# Ignore WIP or temp dev files with uppercase names
|
|
28
|
-
|
|
27
|
+
# Ignore WIP or temp dev files with uppercase names, at the repo root only.
|
|
28
|
+
# Anchored because core.ignoreCase is true on macOS/Windows checkouts: git
|
|
29
|
+
# casefolds the [A-Z] class, so an unanchored pattern silently swallowed every
|
|
30
|
+
# new lowercase .md anywhere in the tree (docs/*.md included).
|
|
31
|
+
/[A-Z]*.md
|
|
32
|
+
|
|
33
|
+
# Unredacted security notes stay local; publish redacted summaries only
|
|
34
|
+
*.private.md
|
|
29
35
|
|
|
30
36
|
# Exclusions
|
|
31
37
|
!README.md
|
data/.talismanrc
CHANGED
|
@@ -12,4 +12,17 @@ fileignoreconfig:
|
|
|
12
12
|
checksum: 10c94f802b2fa3a39fa33bf7dc34dac2ecaa2dd453ff97a19313f96a32fadeff
|
|
13
13
|
- filename: examples/encrypted_fields.rb
|
|
14
14
|
checksum: d1bd77f85d951d367e1c2bfd066a1d68d5f486346ee479121a3d5dcc2560bf52
|
|
15
|
+
# SHA-pinned actions read as "hex encoded text" to talisman; the pin is the point.
|
|
16
|
+
- filename: .github/workflows/claude.yml
|
|
17
|
+
checksum: 3a7acf45fb032644c40bad629ba6c0271689a1233ef6893aba3caf03f6327b50
|
|
18
|
+
- filename: .github/workflows/claude-code-review.yml
|
|
19
|
+
checksum: 698ebf39c1c49a72212cd8d9fd0117aaf15079dcb9f1e22c94dc7a871dd7952e
|
|
20
|
+
- filename: docs/adr/0002-watch-for-private-keys-lua-for-shared-keys.md
|
|
21
|
+
checksum: 0ace51636017e6d0a5b489dc14fc6b684cabd64c6bb706a710f869d31ea5f4f0
|
|
22
|
+
- filename: .github/workflows/ruby-lint.yml
|
|
23
|
+
checksum: b8009bc29189d214229c88f1cf7960c651404e659be74436a79efb130177ff58
|
|
24
|
+
- filename: .github/workflows/ci.yml
|
|
25
|
+
checksum: 0b356104ddf0b192d29b25669c61b17c863eca5de0e36822ea4d7b353d065016
|
|
26
|
+
- filename: .github/workflows/release-gem.yml
|
|
27
|
+
checksum: 1ad4786c939da966b79275105f60005c7a3214f424d5701d8118a7175b087112
|
|
15
28
|
version: ""
|
data/AGENTS.md
CHANGED
|
@@ -21,6 +21,13 @@ Run with `--agent` for token-efficient output (`--agent-focus summary|first-fail
|
|
|
21
21
|
See `bundle exec try --help` for the full CLI, framework integration (`--rspec`,
|
|
22
22
|
`--minitest`), and debugging flags.
|
|
23
23
|
|
|
24
|
+
The whole suite runs in one process, so anything a file sets globally outlives
|
|
25
|
+
it. For encryption keys use the scoped helpers rather than assigning
|
|
26
|
+
`Familia.config.encryption_keys` directly: `set_test_encryption_keys(keys,
|
|
27
|
+
current_version:)` in setup with `clear_test_encryption_keys` in teardown, or
|
|
28
|
+
`with_test_encryption_keys(keys, current_version:) { ... }` for a single
|
|
29
|
+
testcase. See @try/support/helpers/encryption_config.rb.
|
|
30
|
+
|
|
24
31
|
### Changelog
|
|
25
32
|
|
|
26
33
|
Add a changelog fragment (RST) with each user-facing change. See @changelog.d/README.md
|
data/CHANGELOG.rst
CHANGED
|
@@ -7,6 +7,131 @@ The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.1.0/>`
|
|
|
7
7
|
|
|
8
8
|
<!--scriv-insert-here-->
|
|
9
9
|
|
|
10
|
+
.. _changelog-2.12.0:
|
|
11
|
+
|
|
12
|
+
2.12.0 — 2026-08-03
|
|
13
|
+
===================
|
|
14
|
+
|
|
15
|
+
Added
|
|
16
|
+
-----
|
|
17
|
+
|
|
18
|
+
- Added ``Familia::HashKey#claim_field`` and ``#release_field`` for server-side compare-and-set/compare-and-delete on single hash fields. Raises ``Familia::OperationModeError`` in pipelines/transactions.
|
|
19
|
+
- Added generated ``claim_unique_<index>!`` and ``release_unique_<index>!`` instance methods with automatic partial claim rollback on unique index save collisions. #353
|
|
20
|
+
- Added tryout test helpers (``set_test_encryption_keys``, ``clear_test_encryption_keys``, ``with_test_encryption_keys``) to safely manage encryption key configurations during test runs. #363
|
|
21
|
+
- Added ``Familia::MultiResult#aborted?`` to distinguish WATCH aborts from individual command errors.
|
|
22
|
+
- Added ``Familia::MultiResult#inspect`` for log-safe, compact transaction outcome summaries.
|
|
23
|
+
- Added ``max_length:`` option to ``SortedSet`` and ``ListKey`` to automatically cap collection sizes at write time (retaining newest N elements). #351
|
|
24
|
+
- Added ``DataType#max_length`` to query configured collection caps, with definition-time validation of the parameter. #351
|
|
25
|
+
- Added ``SortedSet#enforce_max_length!`` and ``ListKey#enforce_max_length!`` to trim existing collections. #351
|
|
26
|
+
- Added ``max_length:`` option to ``participates_in`` and ``class_participates_in``. #351
|
|
27
|
+
- Added ``Familia::Features::Housekeeping::EnforceCollectionCaps`` chore class to support bulk cap enforcement. #351
|
|
28
|
+
- Added ``encryption_personalization_history`` setting to support key personalization rotation for XChaCha20-Poly1305 providers. #333
|
|
29
|
+
- Added ``limit:``, ``offset:``, and ``each_<collection>_with_permission`` to stream permission-filtered collection members via ``ZSCAN`` with O(1) memory. #309
|
|
30
|
+
|
|
31
|
+
Changed
|
|
32
|
+
-------
|
|
33
|
+
|
|
34
|
+
- Unique index updates (``add_to_class_<index>``, ``update_in_class_<index>``) now raise ``Familia::OperationModeError`` inside transactions unless the written value was previously claimed. #353
|
|
35
|
+
- Retained ``guard_unique_indexes!`` for fast-fail read checks before acquiring index claims. #353
|
|
36
|
+
- Calls to ``remove_from_class_*`` and class-level ``destroy!`` no longer evict index entries that point to different identifiers. #353
|
|
37
|
+
- ``Familia::MultiResult#results`` now always returns an ``Array`` (empty instead of ``nil`` on transaction abort) to prevent upstream crashes.
|
|
38
|
+
- ``Familia::MultiResult#to_h`` now includes an ``:aborted`` boolean key.
|
|
39
|
+
- ``Familia::MultiResult`` instances are now read-only, freezing both ``#results`` and ``#errors``.
|
|
40
|
+
- ``SortedSet#increment`` now runs the ``warn_if_dirty!`` guard, warning or raising when called on an unsaved parent. #351
|
|
41
|
+
- ``Manager#decrypt`` now handles XChaCha20 provider personalization candidates correctly during decryption walks, matching AES-GCM salt history behavior. #333
|
|
42
|
+
- The request-scoped key cache key now includes a personalization segment to prevent collisions across different rotation candidates. #333
|
|
43
|
+
- ``multi_field_fast_write`` now raises ``Familia::IndexedFieldFastWriteError`` if any written field backs a class-level index. #308
|
|
44
|
+
- Fast writer ``field!`` on a class-indexed field now raises ``Familia::IndexedFieldFastWriteError`` inside transactions/pipelines, and raises ``Familia::PersistenceError`` on unsaved records. #308
|
|
45
|
+
- With a blank ``encryption_hkdf_salt``, ``Manager#encrypt`` now raises ``EncryptionError`` when the request-cache key is built rather than at key derivation. The raise happens earlier and now also fires on what would previously have been a warm-cache hit; correctly configured deployments see no change. #380
|
|
46
|
+
|
|
47
|
+
Removed
|
|
48
|
+
-------
|
|
49
|
+
|
|
50
|
+
- Removed the unused ``ScoreEncoding.category_score_range`` method.
|
|
51
|
+
- Removed unused ``csv`` and ``stringio`` runtime dependencies from the gemspec. #354
|
|
52
|
+
- Removed dead private helper methods ``Horreum::define_attr_accessor_methods``, ``remove_stale_collection_member``, and ``define_fast_writer_method``. #347, #308
|
|
53
|
+
|
|
54
|
+
Fixed
|
|
55
|
+
-----
|
|
56
|
+
|
|
57
|
+
- Fixed ``decrby`` and ``decr`` (and aliases) to correctly use ``HINCRBY`` with a negated amount and added client-side integer validation.
|
|
58
|
+
- Fixed ``encryption_info`` to reference the correct provider APIs and accurately expose ``key_size``.
|
|
59
|
+
- Fixed a TOCTOU race in ``unique_index`` by enforcing server-side CAS claims using Lua before opening transactions, raising ``Familia::RecordExistsError`` on collision. #353
|
|
60
|
+
- Fixed ``remove_from_class_*`` and ``update_in_class_*`` to use ownership-checked deletes, preventing accidental deletion of other records' valid entries. #353
|
|
61
|
+
- Fixed process-global encryption configuration leaks across tryouts by using scoped helpers and restoring baselines. #363
|
|
62
|
+
- Fixed test isolation in ``real_feature_integration_try.rb`` and ``module_loading_try.rb`` by explicitly managing encryption key rings. #363
|
|
63
|
+
- Fixed fiber-local key cache teardowns to clear the correct request cache key. #363
|
|
64
|
+
- Fixed claim leaks on unpersisted records in ``update_in_<scope>_<index_name>`` by running the persisted-record guard before checking claims. #370
|
|
65
|
+
- Fixed ``ConcealedString`` by removing a redundant and non-functional GC finalizer. #359
|
|
66
|
+
- Fixed ``Familia::MultiResult`` to prevent ``NoMethodError`` crashes on WATCH-aborted transactions. #355
|
|
67
|
+
- Fixed ``SecureXChaCha20Poly1305Provider#derive_key`` to avoid mutating the receiver context string and handle non-String contexts correctly. #356
|
|
68
|
+
- Fixed ``SortedSet#increment`` inside transactions/pipelines to safely return the future instead of calling ``to_f`` prematurely. #351
|
|
69
|
+
- Fixed long-ignored ``:maxlength`` spelling to explicitly warn at definition time, prompting rename to ``max_length:``. #351
|
|
70
|
+
- Fixed ``Lock#acquire`` with a positive TTL to run as a single atomic ``SET NX EX`` command. #347
|
|
71
|
+
- Fixed ``DatabaseLogger.sample_rate`` assignment to validate and clamp input values, preventing crashes on the hot path. #347
|
|
72
|
+
- Fixed ``SingleUseRedactedString`` to be loaded automatically by ``require 'familia'``. #347
|
|
73
|
+
- Fixed memory overhead in ``<collection>_with_permission`` queries by batching and paging internally via ``ZRANGEBYSCORE ... LIMIT``. #309
|
|
74
|
+
- Fixed performance by removing redundant post-save ``update_all_indexes`` calls inside relationships save. #307
|
|
75
|
+
- Fixed partial write paths (``commit_fields``, ``save_fields``, ``multi_field_update``) to safely guard and claim unique indexes before executing writes. #308
|
|
76
|
+
- Fixed fast writers (``field!``) on indexed fields to claim and update the index atomically before execution. #308
|
|
77
|
+
|
|
78
|
+
Security
|
|
79
|
+
--------
|
|
80
|
+
|
|
81
|
+
- Enforced field-type semantics in ``multi_field_update`` and ``multi_field_fast_write`` to prevent writing plaintext to encrypted fields or persisting transient fields.
|
|
82
|
+
- Enforced loud failures for invalid permission symbol lookups in ``Relationships::ScoreEncoding`` to prevent silent misconfigurations.
|
|
83
|
+
- Pinned GitHub Workflows holding ``CLAUDE_CODE_OAUTH_TOKEN`` to immutable release commit SHAs.
|
|
84
|
+
- The encrypt-path request-cache key now resolves the HKDF salt through the fail-closed ``current_hkdf_salt`` accessor instead of the permissive candidate list's head (``hkdf_salts.first``). Previously, with a blank ``encryption_hkdf_salt``, a decrypt inside ``with_request_cache`` could warm an entry keyed on a historical salt that a subsequent encrypt would silently reuse -- because the cache lookup precedes derivation, the blank-salt refusal in the provider never fired. Encrypts now refuse a blank salt even against a warm cache. #380
|
|
85
|
+
|
|
86
|
+
Documentation
|
|
87
|
+
-------------
|
|
88
|
+
|
|
89
|
+
- Replaced fabricated/incorrect examples in ``docs/overview.md`` and RDoc comments with accurate, tested examples for permission management and relationships.
|
|
90
|
+
- Documented that ``<collection>_with_permission`` requires atomic flags and rejects role symbols.
|
|
91
|
+
- Corrected the error message for ``guard_allowed_fields!``.
|
|
92
|
+
- Documented ``PERMISSION_CATEGORIES`` and exclusive permission tiers.
|
|
93
|
+
- Fixed incorrect connection provider examples in docs.
|
|
94
|
+
- Updated encryption guides to cover personalization history and rotation.
|
|
95
|
+
|
|
96
|
+
AI Assistance
|
|
97
|
+
-------------
|
|
98
|
+
|
|
99
|
+
- Core fixes, tryout coverage (120+ test cases), and documentation updates implemented with AI assistance.
|
|
100
|
+
|
|
101
|
+
.. _changelog-2.11.2:
|
|
102
|
+
|
|
103
|
+
2.11.2 — 2026-07-05
|
|
104
|
+
===================
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
Changed
|
|
108
|
+
-------
|
|
109
|
+
|
|
110
|
+
- ``to_h_for_storage`` omits nil fields; every write path removes a field that has
|
|
111
|
+
become nil. ``save``/``commit_fields`` do a full overwrite (the stored hash
|
|
112
|
+
matches the in-memory object, so a field nil in memory is deleted);
|
|
113
|
+
``save_fields``/``multi_field_update``/``multi_field_fast_write`` delete a named
|
|
114
|
+
field passed as nil. ``to_h`` still returns every declared field, nils included.
|
|
115
|
+
|
|
116
|
+
- Claim caveat: a full ``save``/``commit_fields`` of a stale copy clears a field
|
|
117
|
+
another writer claimed via ``HSETNX``. To claim and update without disturbing
|
|
118
|
+
it, use the targeted writers or ``refresh!`` first.
|
|
119
|
+
|
|
120
|
+
Fixed
|
|
121
|
+
-----
|
|
122
|
+
|
|
123
|
+
- Nil-valued fields are no longer stored as the JSON string ``"null"``. Because a
|
|
124
|
+
hash has no native NULL, this left declared fields perpetually present, breaking
|
|
125
|
+
``HSETNX``/``HEXISTS`` atomic-claim patterns and wasting memory. Nil fields are
|
|
126
|
+
now omitted, and clearing a field to nil removes it from storage (``HDEL``), so
|
|
127
|
+
absence again means "no value". No migration required: stale ``"null"`` values
|
|
128
|
+
are cleaned up on the next save and already decode back to ``nil`` on read.
|
|
129
|
+
|
|
130
|
+
AI Assistance
|
|
131
|
+
-------------
|
|
132
|
+
|
|
133
|
+
- Investigation, implementation, and tryouts coverage produced with Claude Code.
|
|
134
|
+
|
|
10
135
|
.. _changelog-2.11.1:
|
|
11
136
|
|
|
12
137
|
2.11.1 — 2026-07-04
|
data/Gemfile
CHANGED
|
@@ -5,7 +5,7 @@ source 'https://rubygems.org'
|
|
|
5
5
|
gemspec
|
|
6
6
|
|
|
7
7
|
group :test do
|
|
8
|
-
gem 'concurrent-ruby', '~> 1.3.
|
|
8
|
+
gem 'concurrent-ruby', '~> 1.3.8', require: false
|
|
9
9
|
gem 'ruby-prof'
|
|
10
10
|
gem 'stackprof'
|
|
11
11
|
gem 'timecop', require: false
|
|
@@ -26,7 +26,7 @@ group :development, :test do
|
|
|
26
26
|
gem 'rake', '~> 13.0', require: false
|
|
27
27
|
gem 'redcarpet', require: false
|
|
28
28
|
gem 'reek', require: false
|
|
29
|
-
gem 'rubocop', '~> 1.88.
|
|
29
|
+
gem 'rubocop', '~> 1.88.2', require: false
|
|
30
30
|
gem 'rubocop-performance', require: false
|
|
31
31
|
gem 'rubocop-thread_safety', require: false
|
|
32
32
|
gem 'ruby-lsp', require: false
|
data/Gemfile.lock
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
familia (2.
|
|
4
|
+
familia (2.12.0)
|
|
5
5
|
concurrent-ruby (~> 1.3)
|
|
6
6
|
connection_pool (>= 2.4, < 4.0)
|
|
7
|
-
csv (~> 3.3)
|
|
8
7
|
json_schemer (~> 2.0)
|
|
9
8
|
logger (~> 1.7)
|
|
10
9
|
oj (~> 3.16)
|
|
11
10
|
redis (>= 5.0, < 6.0)
|
|
12
|
-
stringio (~> 3.1.1)
|
|
13
11
|
uri-valkey (~> 1.4)
|
|
14
12
|
|
|
15
13
|
GEM
|
|
@@ -19,9 +17,8 @@ GEM
|
|
|
19
17
|
base64 (0.3.0)
|
|
20
18
|
benchmark (0.5.0)
|
|
21
19
|
bigdecimal (4.1.2)
|
|
22
|
-
concurrent-ruby (1.3.
|
|
20
|
+
concurrent-ruby (1.3.8)
|
|
23
21
|
connection_pool (3.0.2)
|
|
24
|
-
csv (3.3.5)
|
|
25
22
|
date (3.5.1)
|
|
26
23
|
debug (1.11.1)
|
|
27
24
|
irb (~> 1.10)
|
|
@@ -66,17 +63,17 @@ GEM
|
|
|
66
63
|
prism (>= 1.3.0)
|
|
67
64
|
rdoc (>= 4.0.0)
|
|
68
65
|
reline (>= 0.4.2)
|
|
69
|
-
json (2.
|
|
66
|
+
json (2.20.0)
|
|
70
67
|
json_schemer (2.5.0)
|
|
71
68
|
bigdecimal
|
|
72
69
|
hana (~> 1.3)
|
|
73
70
|
regexp_parser (~> 2.0)
|
|
74
71
|
simpleidn (~> 0.2)
|
|
75
|
-
language_server-protocol (3.17.0.
|
|
72
|
+
language_server-protocol (3.17.0.6)
|
|
76
73
|
lint_roller (1.1.0)
|
|
77
74
|
logger (1.7.0)
|
|
78
75
|
minitest (5.27.0)
|
|
79
|
-
oj (3.17.
|
|
76
|
+
oj (3.17.4)
|
|
80
77
|
bigdecimal (>= 3.0)
|
|
81
78
|
ostruct (>= 0.2)
|
|
82
79
|
ostruct (0.6.3)
|
|
@@ -98,7 +95,7 @@ GEM
|
|
|
98
95
|
rake (13.4.2)
|
|
99
96
|
rbnacl (7.1.2)
|
|
100
97
|
ffi (~> 1)
|
|
101
|
-
rbs (4.0.
|
|
98
|
+
rbs (4.0.3)
|
|
102
99
|
logger
|
|
103
100
|
prism (>= 1.6.0)
|
|
104
101
|
tsort
|
|
@@ -134,7 +131,7 @@ GEM
|
|
|
134
131
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
135
132
|
rspec-support (~> 3.13.0)
|
|
136
133
|
rspec-support (3.13.7)
|
|
137
|
-
rubocop (1.88.
|
|
134
|
+
rubocop (1.88.2)
|
|
138
135
|
json (~> 2.3)
|
|
139
136
|
language_server-protocol (~> 3.17.0.2)
|
|
140
137
|
lint_roller (~> 1.1.0)
|
|
@@ -145,7 +142,7 @@ GEM
|
|
|
145
142
|
rubocop-ast (>= 1.49.0, < 2.0)
|
|
146
143
|
ruby-progressbar (~> 1.7)
|
|
147
144
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
148
|
-
rubocop-ast (1.
|
|
145
|
+
rubocop-ast (1.50.0)
|
|
149
146
|
parser (>= 3.3.7.2)
|
|
150
147
|
prism (~> 1.7)
|
|
151
148
|
rubocop-performance (1.26.1)
|
|
@@ -156,7 +153,7 @@ GEM
|
|
|
156
153
|
lint_roller (~> 1.1)
|
|
157
154
|
rubocop (~> 1.72, >= 1.72.1)
|
|
158
155
|
rubocop-ast (>= 1.44.0, < 2.0)
|
|
159
|
-
ruby-lsp (0.26.
|
|
156
|
+
ruby-lsp (0.26.10)
|
|
160
157
|
language_server-protocol (~> 3.17.0)
|
|
161
158
|
prism (>= 1.2, < 2.0)
|
|
162
159
|
rbs (>= 3, < 5)
|
|
@@ -166,7 +163,7 @@ GEM
|
|
|
166
163
|
ruby-progressbar (1.13.0)
|
|
167
164
|
simpleidn (0.2.3)
|
|
168
165
|
stackprof (0.2.28)
|
|
169
|
-
stringio (3.
|
|
166
|
+
stringio (3.2.0)
|
|
170
167
|
timecop (0.9.11)
|
|
171
168
|
tryouts (3.7.1)
|
|
172
169
|
concurrent-ruby (~> 1.0, < 2)
|
|
@@ -185,7 +182,7 @@ GEM
|
|
|
185
182
|
unicode-emoji (~> 4.1)
|
|
186
183
|
unicode-emoji (4.2.0)
|
|
187
184
|
uri-valkey (1.4.0)
|
|
188
|
-
yard (0.9.
|
|
185
|
+
yard (0.9.45)
|
|
189
186
|
zeitwerk (2.8.2)
|
|
190
187
|
|
|
191
188
|
PLATFORMS
|
|
@@ -194,7 +191,7 @@ PLATFORMS
|
|
|
194
191
|
|
|
195
192
|
DEPENDENCIES
|
|
196
193
|
benchmark (~> 0.4)
|
|
197
|
-
concurrent-ruby (~> 1.3.
|
|
194
|
+
concurrent-ruby (~> 1.3.8)
|
|
198
195
|
debug
|
|
199
196
|
dry-configurable (>= 1.3, < 1.5)
|
|
200
197
|
familia!
|
|
@@ -204,7 +201,7 @@ DEPENDENCIES
|
|
|
204
201
|
rbnacl (~> 7.1, >= 7.1.1)
|
|
205
202
|
redcarpet
|
|
206
203
|
reek
|
|
207
|
-
rubocop (~> 1.88.
|
|
204
|
+
rubocop (~> 1.88.2)
|
|
208
205
|
rubocop-performance
|
|
209
206
|
rubocop-thread_safety
|
|
210
207
|
ruby-lsp
|
data/README.md
CHANGED
|
@@ -377,13 +377,24 @@ end
|
|
|
377
377
|
```ruby
|
|
378
378
|
require 'connection_pool'
|
|
379
379
|
|
|
380
|
+
POOLS = {}
|
|
381
|
+
POOLS_MUTEX = Mutex.new
|
|
382
|
+
|
|
380
383
|
Familia.connection_provider = lambda do |uri|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
+
POOLS_MUTEX.synchronize do
|
|
385
|
+
POOLS[uri] ||= ConnectionPool::Wrapper.new(size: 10, timeout: 5) do
|
|
386
|
+
Redis.new(url: uri)
|
|
387
|
+
end
|
|
388
|
+
end
|
|
384
389
|
end
|
|
385
390
|
```
|
|
386
391
|
|
|
392
|
+
Build each pool once, outside the lambda, and return a `ConnectionPool::Wrapper`
|
|
393
|
+
— it checks a connection out for the duration of each command and checks it back
|
|
394
|
+
in afterwards. Returning `pool.with { |conn| conn }` instead hands back a
|
|
395
|
+
connection the pool already considers free, so concurrent callers share it. See
|
|
396
|
+
[the provider contract](docs/reference/api-technical.md#provider-contract).
|
|
397
|
+
|
|
387
398
|
### Encryption Setup
|
|
388
399
|
|
|
389
400
|
```ruby
|
data/changelog.d/README.md
CHANGED
|
@@ -4,64 +4,56 @@ This directory contains changelog fragments managed by [Scriv](https://scriv.rea
|
|
|
4
4
|
|
|
5
5
|
## Our Approach
|
|
6
6
|
|
|
7
|
-
Changelogs are for humans and agents, not just machines. We follow
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* `
|
|
21
|
-
* `
|
|
22
|
-
* `
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Include technical details to help developers update to the new version. Start with a specific introduction, e.g. "This version introduces significant improvements to Familia's feature system, making it easier to organize and use features across complex projects.". Including code snippets and multi-line content that is too detailed for the CHANGELOG.
|
|
40
|
-
|
|
41
|
-
Use the content of an existing `docs/migrating/vMajor.Minor.Patch*.md file as a reference.
|
|
42
|
-
|
|
43
|
-
Compare the headers of your draft content with the headers of the previous migration guide to make sure it does not repeat or overlap.
|
|
44
|
-
|
|
45
|
-
4. **Commit with Your Code:**
|
|
46
|
-
```bash
|
|
47
|
-
git add changelog.d/YYYYMMDD_HHmmss_username_branch.rst [docs/migrating/v2.0.0-pre.md]
|
|
48
|
-
git commit
|
|
49
|
-
```
|
|
7
|
+
Changelogs are for humans and agents, not just machines. We follow [Keep a Changelog](https://keepachangelog.com) and semver to ensure clear, consistent, and useful release notes.
|
|
8
|
+
|
|
9
|
+
We use a fragment-based workflow with `scriv`. Each developer includes a small, focused changelog fragment with their pull request. At release time, these are compiled into the main changelog.
|
|
10
|
+
|
|
11
|
+
Benefits:
|
|
12
|
+
- **No Merge Conflicts:** Developers work in parallel without conflicting over a single file.
|
|
13
|
+
- **Improved DX:** Creating a small fragment is simple and repeatable.
|
|
14
|
+
- **AI Transparency:** Briefly notes AI involvement without cluttering technical sections.
|
|
15
|
+
- **Consistency:** Automation maintains a unified structure.
|
|
16
|
+
|
|
17
|
+
### Relevant Paths
|
|
18
|
+
|
|
19
|
+
* `changelog.d/` - Fragment directory (e.g. `changelog.d/YYYYMMDD_HHmmss_username_branch.rst`)
|
|
20
|
+
* `docs/migrating/` - Migration guides (e.g. `docs/migrating/v2.0.0-pre.md`)
|
|
21
|
+
* `CHANGELOG.rst` - The full changelog (reverse chronological, large file; read only the top 100 lines default)
|
|
22
|
+
* `changelog.d/scriv.ini` - Scriv configuration
|
|
23
|
+
|
|
24
|
+
## Add a Changelog Entry
|
|
25
|
+
|
|
26
|
+
1. **Create a New Fragment:**
|
|
27
|
+
```bash
|
|
28
|
+
scriv create
|
|
29
|
+
```
|
|
30
|
+
2. **Edit the Fragment:**
|
|
31
|
+
Open the new `.rst` file and write your entry under the relevant category using the guidelines below.
|
|
32
|
+
3. **Add or Update Migrating Guide (Optional):**
|
|
33
|
+
If the change requires developer action to upgrade, add or update a guide in `docs/migrating/`. Use existing guides as a reference and ensure headers do not repeat.
|
|
34
|
+
4. **Commit with Your Code:**
|
|
35
|
+
```bash
|
|
36
|
+
git add changelog.d/YYYYMMDD_HHmmss_username_branch.rst [docs/migrating/v2.0.0-pre.md]
|
|
37
|
+
git commit
|
|
38
|
+
```
|
|
50
39
|
|
|
51
40
|
## Fragment Guidelines
|
|
52
41
|
|
|
53
42
|
- **One Fragment Per Change:** Keep each fragment focused on a single feature, fix, or improvement.
|
|
54
|
-
- **
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- **
|
|
59
|
-
- **
|
|
60
|
-
|
|
43
|
+
- **Reference Context:** Include issue or PR numbers. Scriv will automatically link them. (e.g., `PR #123`).
|
|
44
|
+
|
|
45
|
+
## Content Guidelines
|
|
46
|
+
|
|
47
|
+
- **Target the Consumer:** Focus exclusively on external, breaking, or actionable behavior. Omit internal implementation steps, development metadata, and agent logs.
|
|
48
|
+
- **Impact-Driven Filtering:** Focus strictly on technical facts (method/class signatures, parameters, exceptions, issues resolved) and eliminate explanatory "how" or "why" narratives.
|
|
49
|
+
- **Good:** "Added ``Familia::HashKey#claim_field`` and ``#release_field`` for single-hash server-side CAS/CAD operations. Raises ``Familia::OperationModeError`` in pipelines/transactions."
|
|
50
|
+
- **Bad:** "We found a race condition during an audit, so we added a nice compare-and-set wrapper called `#claim_field` to allow callers to safely claim a field in single hash fields."
|
|
51
|
+
- **Process Log Exclusion:** Remove all development metadata (such as tool-specific implementation notes, agent logs, and audit timelines) that do not change library APIs or behavior.
|
|
52
|
+
- **Maintain Consistency:** Match the terse style, semantic classification, and spacing of previous changelog versions.
|
|
61
53
|
|
|
62
|
-
|
|
54
|
+
## Categories
|
|
63
55
|
|
|
64
|
-
Use these
|
|
56
|
+
Use these standard headers in your fragment:
|
|
65
57
|
|
|
66
58
|
- **Added**: New features or capabilities.
|
|
67
59
|
- **Changed**: Changes to existing functionality.
|
|
@@ -70,8 +62,8 @@ Use these categories:
|
|
|
70
62
|
- **Fixed**: Bug fixes.
|
|
71
63
|
- **Security**: Security-related improvements.
|
|
72
64
|
- **Documentation**: Documentation improvements.
|
|
73
|
-
- **AI Assistance**:
|
|
65
|
+
- **AI Assistance**: Terse, single-sentence acknowledgment of AI assistance for the change. Do not duplicate technical details already listed in other categories.
|
|
74
66
|
|
|
75
67
|
## Release Process
|
|
76
68
|
|
|
77
|
-
At release
|
|
69
|
+
At release, run `scriv collect` to aggregate all fragments into `CHANGELOG.rst`. The version is parsed automatically from `lib/familia/version.rb`.
|