partition_gardener 0.3.5 → 0.3.7
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/CHANGELOG.md +21 -0
- data/README.md +2 -2
- data/docs/THIRD_PARTY_LICENSE_MANIFEST.tsv +18 -19
- data/docs/application_contract.md +29 -3
- data/docs/audit_reference.md +1 -1
- data/docs/changelogs/20260709120900_partition-engines-guide.md +1 -1
- data/docs/changelogs/20260813142300_rebalance-before-archive-attach.md +19 -0
- data/docs/changelogs/20260813144516_relock-appraisal-advisory-json.md +21 -0
- data/docs/changelogs/20260902114500_align-child-columns-before-attach.md +19 -0
- data/docs/changelogs/20260902124500_cut-patch-release-0-3-4.md +24 -0
- data/docs/changelogs/20260909143500_occupied-window-current-origin.md +19 -0
- data/docs/changelogs/20260909154900_tail-slot-rfc.md +21 -0
- data/docs/changelogs/20260909162554_high-end-future-occupancy.md +21 -0
- data/docs/changelogs/20260909164000_shipped-contract-rfcs.md +21 -0
- data/docs/changelogs/20260909165500_cut-patch-release-0-3-5.md +24 -0
- data/docs/changelogs/20260916144600_public-identifiers-contract.md +23 -0
- data/docs/changelogs/20261005135700_checkpoint-table-name.md +23 -0
- data/docs/changelogs/20261005141621_cut-patch-release-0-3-6.md +23 -0
- data/docs/changelogs/20261021220000_cut-patch-release-0-3-7.md +24 -0
- data/docs/configuration.md +3 -1
- data/docs/dependencies/20260813144516_json-cve-2026-71847.md +27 -0
- data/docs/issues/20260909143500_occupied-window-current-origin.md +25 -0
- data/docs/issues/20260909164000_shipped-contract-rfcs.md +25 -0
- data/docs/issues/20260916113300_opaque-composite-public-ids.md +55 -0
- data/docs/issues/20260917123253_ci-drop-automatic-dependency-audit.md +28 -0
- data/docs/operations.md +1 -1
- data/docs/partition_landscape.md +6 -4
- data/docs/reviews/20261021220000_engineering-audit-0-3-7.md +30 -0
- data/docs/reviews/20261028075216_engineering-audit-release-preparation.md +35 -0
- data/docs/reviews/20261029150855_engineering-audit-release-preparation.md +43 -0
- data/docs/schemas/partition_garden.schema.json +16 -0
- data/lib/partition_gardener/archive_retention.rb +7 -3
- data/lib/partition_gardener/config_document.rb +4 -0
- data/lib/partition_gardener/configuration.rb +9 -1
- data/lib/partition_gardener/date_calendar.rb +2 -5
- data/lib/partition_gardener/gap_detection.rb +1 -1
- data/lib/partition_gardener/migration/hot_switch_concern.rb +24 -15
- data/lib/partition_gardener/plan_applier.rb +17 -3
- data/lib/partition_gardener/sql_run_record_store.rb +40 -5
- data/lib/partition_gardener/version.rb +1 -1
- data/sig/partition_gardener.rbs +2 -2
- metadata +22 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e5f9084c2b05bdad581f87e5b137cc7321106f2a4a39e3d52def523acd74f0b7
|
|
4
|
+
data.tar.gz: 86ba83786f0cf06729e041e758e8034253e549677237160bb3dc0c09716ec071
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c3c13183c16a47fc4b479a7c4311e689a2081e9dddc0c60f8a590c5e4cdffa4e56db1f8e270e7cf4119772398f1f286baaa4ab985b20ef743b8fa2854a38b47e
|
|
7
|
+
data.tar.gz: 702c2a0f9d29d5c0a63894172ced8ab62cf47f70ab84f0fbcd02a9e648455cfed78927d187ca41538612140c7271b51363937fa60a1be501a24e4c3bb3ac42a5
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.3.7 (2026-10-29)
|
|
6
|
+
|
|
7
|
+
- Fix rebalance resume so phase `detach` still runs detach and drain until the record advances to `segments`
|
|
8
|
+
- Refuse `CREATE TABLE IF NOT EXISTS … PARTITION OF` when a detached table already owns the planned child name
|
|
9
|
+
- Drop detached remove candidates only when they hold zero rows
|
|
10
|
+
- Rename hot-switch children when the live table name is a suffix of the shadow prefix (for example `p_events` → `events`)
|
|
11
|
+
- Repoint serial sequences after hot-switch by setting `nextval` default and `setval` on the live table
|
|
12
|
+
- Fail closed in `sync_delta_data` when `sync_stale_column` is missing from source or target
|
|
13
|
+
- Sort gap detection bounds with native `Comparable` order so integer windows are not lexicographic
|
|
14
|
+
- Advance `DateCalendar.add_years` through leap days via `Date#>>`
|
|
15
|
+
- Notify detach versus drop for archive retention when `retention_keep_table` is set
|
|
16
|
+
- Export and accept `active_id_lo`, `active_id_width`, `current_band_size`, and `archive_band_size` in JSON registry documents
|
|
17
|
+
- Align README Ruby requirement and RBS `statement_timeout` types with the gemspec
|
|
18
|
+
|
|
19
|
+
## 0.3.6 (2026-10-05)
|
|
20
|
+
|
|
21
|
+
- Store rebalance checkpoints in `partition_gardener_checkpoints` by default (previously `partition_gardener_run_records`)
|
|
22
|
+
- Add `run_record_table_name` so a host can keep another checkpoint table name
|
|
23
|
+
- Rename leftover `partition_gardener_runs` or `partition_gardener_run_records` on first use of the default table name
|
|
24
|
+
- Document public identifiers for partitioned rows: four contracts, Rails signed_id versus scalar primary_key, fail-closed decode ([application_contract.md](docs/application_contract.md#public-identifiers))
|
|
25
|
+
|
|
5
26
|
## 0.3.5 (2026-09-09)
|
|
6
27
|
|
|
7
28
|
- Keep attached monthly children that already cover the start of the sliding-window active range, and fill the remainder as `_open` rather than overlapping `_current`
|
data/README.md
CHANGED
|
@@ -6,7 +6,7 @@ PostgreSQL partition lifecycle: archive, current, and future zones, heat-driven
|
|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
9
|
-
- Ruby >= 3.
|
|
9
|
+
- Ruby >= 3.4
|
|
10
10
|
- PostgreSQL with declarative partitioning
|
|
11
11
|
- `pg` gem (runtime dependency)
|
|
12
12
|
- Rails >= 7.1 optional — railtie loads when Rails is present and sets Active Record connection plus `Time.zone.today`
|
|
@@ -37,7 +37,7 @@ Complements migration gems (e.g. [pg_party](https://github.com/rkrage/pg_party))
|
|
|
37
37
|
### Application and migration
|
|
38
38
|
|
|
39
39
|
- [docs/cutover.md](docs/cutover.md) — hot-switch playbook and template upgrades
|
|
40
|
-
- [docs/application_contract.md](docs/application_contract.md) — writes, moves, routing when the key is missing, bulk load, replicas
|
|
40
|
+
- [docs/application_contract.md](docs/application_contract.md) — writes, moves, routing when the key is missing, public identifiers, bulk load, replicas
|
|
41
41
|
- [docs/naming.md](docs/naming.md) — child partition naming catalog
|
|
42
42
|
- [docs/host_testing.md](docs/host_testing.md) — CI and staging for host apps
|
|
43
43
|
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
bundle gem version licenses
|
|
2
|
-
root activemodel 8.1.
|
|
3
|
-
root activerecord 8.1.
|
|
4
|
-
root activesupport 8.1.
|
|
2
|
+
root activemodel 8.1.4 MIT
|
|
3
|
+
root activerecord 8.1.4 MIT
|
|
4
|
+
root activesupport 8.1.4 MIT
|
|
5
5
|
root appraisal 2.5.0 MIT
|
|
6
6
|
root ast 2.4.3 MIT
|
|
7
7
|
root base64 0.3.0 Ruby|BSD-2-Clause
|
|
8
|
-
root bigdecimal 4.1.
|
|
8
|
+
root bigdecimal 4.1.3 Ruby|BSD-2-Clause
|
|
9
9
|
root bundler 4.0.16 MIT
|
|
10
10
|
root concurrent-ruby 1.3.8 MIT
|
|
11
11
|
root connection_pool 3.0.2 MIT
|
|
12
12
|
root diff-lcs 1.6.2 MIT|Artistic-1.0-Perl|GPL-2.0-or-later
|
|
13
13
|
root drb 2.2.3 Ruby|BSD-2-Clause
|
|
14
14
|
root i18n 1.15.2 MIT
|
|
15
|
-
root json
|
|
15
|
+
root json 3.1.0 Ruby
|
|
16
16
|
root language_server-protocol 3.17.0.6 MIT
|
|
17
17
|
root lint_roller 1.1.0 MIT
|
|
18
18
|
root logger 1.7.0 Ruby|BSD-2-Clause
|
|
19
19
|
root minitest 6.0.6 MIT
|
|
20
|
-
root parallel 2.
|
|
21
|
-
root parser 3.3.
|
|
22
|
-
root partition_gardener 0.3.
|
|
20
|
+
root parallel 2.3.0 MIT
|
|
21
|
+
root parser 3.3.13.0 MIT
|
|
22
|
+
root partition_gardener 0.3.7 MIT
|
|
23
23
|
root pg 1.6.3 BSD-2-Clause
|
|
24
|
-
root polyrun 2.2.
|
|
24
|
+
root polyrun 2.2.5 MIT
|
|
25
25
|
root prism 1.9.0 MIT
|
|
26
26
|
root prosopite 2.2.0 Apache-2.0
|
|
27
27
|
root racc 1.8.1 Ruby|BSD-2-Clause
|
|
@@ -29,33 +29,32 @@ root rack 3.2.7 MIT
|
|
|
29
29
|
root rainbow 3.1.1 MIT
|
|
30
30
|
root rake 13.4.2 MIT
|
|
31
31
|
root rbs 4.2.0 BSD-2-Clause|Ruby
|
|
32
|
-
root regexp_parser 2.
|
|
32
|
+
root regexp_parser 2.13.1 MIT
|
|
33
33
|
root rspec 3.13.2 MIT
|
|
34
34
|
root rspec-core 3.13.6 MIT
|
|
35
35
|
root rspec-expectations 3.13.5 MIT
|
|
36
36
|
root rspec-mocks 3.13.8 MIT
|
|
37
37
|
root rspec-support 3.13.7 MIT
|
|
38
|
-
root
|
|
39
|
-
root rubocop 1.88.2 MIT
|
|
38
|
+
root rubocop 1.91.0 MIT
|
|
40
39
|
root rubocop-ast 1.50.0 MIT
|
|
41
40
|
root rubocop-capybara 2.23.0 MIT
|
|
42
41
|
root rubocop-factory_bot 2.28.0 MIT
|
|
43
42
|
root rubocop-performance 1.26.1 MIT
|
|
44
43
|
root rubocop-rails 2.34.3 MIT
|
|
45
44
|
root rubocop-rspec 3.10.2 MIT
|
|
46
|
-
root rubocop-rspec_rails 2.
|
|
47
|
-
root rubocop-thread_safety 0.
|
|
45
|
+
root rubocop-rspec_rails 2.33.0 MIT
|
|
46
|
+
root rubocop-thread_safety 0.8.0 MIT
|
|
48
47
|
root ruby-progressbar 1.13.0 MIT
|
|
49
48
|
root securerandom 0.4.1 Ruby|BSD-2-Clause
|
|
50
|
-
root standard 1.
|
|
49
|
+
root standard 1.57.0
|
|
51
50
|
root standard-custom 1.0.2 MIT
|
|
52
51
|
root standard-performance 1.9.0 MIT
|
|
53
52
|
root standard-rails 1.6.0 MIT
|
|
54
|
-
root standard-rspec 0.5.
|
|
53
|
+
root standard-rspec 0.5.1 MIT
|
|
55
54
|
root thor 1.5.0 MIT
|
|
56
55
|
root timeout 0.6.1 Ruby|BSD-2-Clause
|
|
57
56
|
root tsort 0.2.0 Ruby|BSD-2-Clause
|
|
58
57
|
root tzinfo 2.0.6 MIT
|
|
59
|
-
root unicode-display_width 3.
|
|
60
|
-
root unicode-emoji 4.
|
|
61
|
-
root uri 1.1.
|
|
58
|
+
root unicode-display_width 3.3.0 MIT
|
|
59
|
+
root unicode-emoji 4.3.0 MIT
|
|
60
|
+
root uri 1.1.2 Ruby|BSD-2-Clause
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Application contract
|
|
2
2
|
|
|
3
|
-
How host applications should behave around partitioned tables: queries, writes, maintenance side effects, bulk load, and replicas. For UI scoping and aggregate snapshots see [partition_landscape.md](partition_landscape.md). For operator runbooks see [operations.md](operations.md).
|
|
3
|
+
How host applications should behave around partitioned tables: queries, writes, public identifiers, maintenance side effects, bulk load, and replicas. For UI scoping and aggregate snapshots see [partition_landscape.md](partition_landscape.md). For operator runbooks see [operations.md](operations.md).
|
|
4
4
|
|
|
5
5
|
## Query and write basics
|
|
6
6
|
|
|
@@ -8,6 +8,7 @@ How host applications should behave around partitioned tables: queries, writes,
|
|
|
8
8
|
- `conflict_key` columns match the parent unique index; updates and deletes use `query_constraints` when the logical id is not globally unique ([partition_landscape.md](partition_landscape.md#rails-application-contract)).
|
|
9
9
|
- Inserts supply a routable partition key value so rows land in named children, not only in `default`.
|
|
10
10
|
- When only a logical id or parent reference is available, follow the recovery ladder in [partition_landscape.md](partition_landscape.md#routing-hints-when-the-key-is-not-in-hand).
|
|
11
|
+
- Public URLs and API ids follow [Public identifiers](#public-identifiers).
|
|
11
12
|
- After maintenance with high `rows_moved`, refresh `id → partition_key` mappings when the partition key can change.
|
|
12
13
|
|
|
13
14
|
## During maintenance (row moves)
|
|
@@ -31,6 +32,31 @@ Duplicate key across children — overlapping manual DDL. Application response:
|
|
|
31
32
|
|
|
32
33
|
Applications should not catch routing errors and retry without the partition key.
|
|
33
34
|
|
|
35
|
+
## Public identifiers
|
|
36
|
+
|
|
37
|
+
Treat database uniqueness, public identifier, routing hint, and authorization as four contracts. PostgreSQL uniqueness on a partitioned parent is composite because the partition key must sit in every unique index. That does not by itself decide what a person sees in a URL or API.
|
|
38
|
+
|
|
39
|
+
When a single sequence or UUIDv7 keeps `id` unique across children, keep that logical id as the application identifier: `self.primary_key = :id` so `to_param` and JSON stay a scalar, not a Rails underscore composite such as `42_100`. Still attach a routing hint on point lookups so `SELECT` can prune. Do not invent that hint from current month.
|
|
40
|
+
|
|
41
|
+
When `id` is unique only inside a child, the public identifier for point lookups must carry every uniqueness column. Prefer one opaque path segment over Rails `extract_value` underscore form (`4_2`) or a separate query parameter the caller can edit independently.
|
|
42
|
+
|
|
43
|
+
Prefer Rails APIs over a homemade encoding:
|
|
44
|
+
|
|
45
|
+
- True composite `primary_key` (array): `signed_id` / `find_signed` or `to_sgid` / `SignedGlobalID`. Both uniqueness columns travel; `find` can prune. `signed_id` uses HMAC SHA256, JSON, and `url_safe: true`. The payload is encoded, not encrypted.
|
|
46
|
+
- Scalar `primary_key = :id` plus `query_constraints`: `signed_id` and `generates_token_for` still sign and find by `id` alone. `query_constraints` never feeds `SELECT`. Sign `[id, partition_key]` with a host `ActiveSupport::MessageVerifier` (`url_safe: true`), or resolve through an unpartitioned mapping table.
|
|
47
|
+
- `has_secure_token` stores a random Base58 mapping value. A unique index on that column alone is illegal on a partitioned parent unless the partition key is in the index. Put the mapping off the partitioned fact table, or keep a globally unique logical id on the fact row.
|
|
48
|
+
- Default `MessageVerifier` is not URL-safe. `signed_id` and `GlobalID::Verifier` opt into `url_safe`. Do not encrypt identifiers with `MessageEncryptor`.
|
|
49
|
+
- Unsigned GlobalID (`gid://app/Event/123/2026-03-15`) and `to_param` underscore composites are tunable. Keep them off public point-lookup URLs.
|
|
50
|
+
- Extra JSON in `generates_token_for` is compared after fetch. It is not a `WHERE` predicate and is plaintext in the token.
|
|
51
|
+
|
|
52
|
+
Active Record 7.1 is this gem's development floor. Composite `find_by_token_for` needs 7.2 or 8.0. Composite `find_signed` wrapping `primary_key => [id]` needs 8.1. Hosts on 7.1 should verify finders before relying on signed composite lookup.
|
|
53
|
+
|
|
54
|
+
After decode, query with both columns and fail closed. Do not fall back to id-only scan. A bad or unsigned token is 404, not a bounded retry across children. Encoding is packaging, not authorization. Lookups still go through an ownership set.
|
|
55
|
+
|
|
56
|
+
List screens still show period, account, or branch in product language ([partition_landscape.md](partition_landscape.md#ui-and-product-surfaces)). Tenant and list keys for hot paths come from session or parent context, not from a tunable URL field. Pagination cursors already belong in the same family as opaque tokens.
|
|
57
|
+
|
|
58
|
+
Gardener does not ship an encoder. Host applications own secrets, token version, and decode.
|
|
59
|
+
|
|
34
60
|
## Bulk import and backfill
|
|
35
61
|
|
|
36
62
|
- Chunk `COPY` or `insert_all` by bucket window within partition bounds (month, week, day).
|
|
@@ -69,7 +95,7 @@ Registry JSON may differ per shard only if layouts differ (unusual).
|
|
|
69
95
|
## Admin and operator surfaces
|
|
70
96
|
|
|
71
97
|
- Default filters: current month or selected tenant, not all history.
|
|
72
|
-
- Global id search is an advanced, slow path; require date or tenant hint, or resolve through a mapping table before scanning children.
|
|
98
|
+
- Global id search is an advanced, slow path; require date or tenant hint, or resolve through a mapping table before scanning children ([Public identifiers](#public-identifiers)).
|
|
73
99
|
- Export flows chunk by bucket; show progress per period.
|
|
74
100
|
- Totals read from snapshot tables with `computed_at`, not live `SUM` across all children or a stale materialized view over the full fact table ([partition_landscape.md](partition_landscape.md#materialized-views)).
|
|
75
101
|
|
|
@@ -79,6 +105,6 @@ See [host_testing.md](host_testing.md) for CI registry fixtures and integration
|
|
|
79
105
|
|
|
80
106
|
## Related
|
|
81
107
|
|
|
82
|
-
- [partition_landscape.md](partition_landscape.md) — pruning, routing layers and hints, UI, snapshots
|
|
108
|
+
- [partition_landscape.md](partition_landscape.md) — pruning, routing layers and hints, UI, snapshots; `query_constraints` versus `SELECT`
|
|
83
109
|
- [cutover.md](cutover.md) — backfill and switch
|
|
84
110
|
- [naming.md](naming.md) — child table names
|
data/docs/audit_reference.md
CHANGED
|
@@ -98,7 +98,7 @@ Per-table metrics (`RunMetrics#to_h`):
|
|
|
98
98
|
|
|
99
99
|
## Run record table
|
|
100
100
|
|
|
101
|
-
When `run_record_enabled`, PostgreSQL table `
|
|
101
|
+
When `run_record_enabled`, PostgreSQL table `partition_gardener_checkpoints` (or `run_record_table_name`) stores:
|
|
102
102
|
|
|
103
103
|
`table_name` — parent.
|
|
104
104
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Rebalance before archive attach
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
Date-range maintenance rebalances the sliding-window tail before it finalizes monthly archives or applies retention. That lets one run detach a current partition that still starts on 1 July, attach a new current partition from 1 August, send July rows to default, and attach a non-overlapping monthly child from default.
|
|
10
|
+
|
|
11
|
+
Archive attach is skipped when the bucket start is at or after the attached current partition lower bound. Those buckets wait until rebalance moves the current span forward. The lower bound is read with Connection.current_partition_lower_bound.
|
|
12
|
+
|
|
13
|
+
## Effects
|
|
14
|
+
|
|
15
|
+
A July-to-August maintenance sequence attaches the July monthly child and a current partition from 1 August.
|
|
16
|
+
|
|
17
|
+
## Source
|
|
18
|
+
|
|
19
|
+
Requested in the partition_gardener sliding-window rollover fix. Specs: spec/integration/sliding_window_maintenance_spec.rb and spec/partition_gardener/attach_retry_spec.rb.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Relock appraisal graphs for json advisory
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
Appraisal lockfiles are part of the CI install graph. After 0.3.3 they must pin partition_gardener 0.3.3 and json 2.21.2 so frozen bundle install and bundle-audit both pass. The dependency audit workflow scans Gemfile.lock and *.gemfile.lock.
|
|
10
|
+
|
|
11
|
+
## Effects
|
|
12
|
+
|
|
13
|
+
Relocked gemfiles/rails72.gemfile.lock, gemfiles/rails8ruby34.gemfile.lock, and gemfiles/rails8ruby4.gemfile.lock. Widened the find in .github/workflows/dependency-audit.yml.
|
|
14
|
+
|
|
15
|
+
## Next
|
|
16
|
+
|
|
17
|
+
Merge the patch so main test and dependency audit jobs install a consistent graph.
|
|
18
|
+
|
|
19
|
+
## Source
|
|
20
|
+
|
|
21
|
+
Triggered by failing Dependency audit and test workflows after the 0.3.3 merge. Advisory note: usr/docs/dependencies/20260813144516_json-cve-2026-71847.md.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Align child columns before attach
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
ATTACH PARTITION now runs additive column align first (default on). CREATE TABLE LIKE and DETACH snapshot columns; a later parent ADD COLUMN does not reach that child. Align adds all missing ordinary columns in one ALTER TABLE statement (skip identity and generated), preserving type, non-default collation, default, and NOT NULL. PostgreSQL rejects the complete statement when existing rows cannot satisfy NOT NULL, so standalone execution does not leave a partial alignment. Extra child columns stay. Existing types and other constraints are not rewritten.
|
|
10
|
+
|
|
11
|
+
Audit warns when an unattached managed child still lags the parent. Built-in strategies filter unrelated prefixed tables and load all candidate column metadata in one catalog query. Custom partition name formatters retain prefix discovery because detached tables have no parent provenance. align_child_columns: false keeps fail-fast attach. JSON registry import rejects non-boolean align_child_columns values.
|
|
12
|
+
|
|
13
|
+
## Effects
|
|
14
|
+
|
|
15
|
+
LIKE and keep-table reattach paths attach after a parent ADD COLUMN without a host workaround. A missing conflict-key column is aligned before its child index is created.
|
|
16
|
+
|
|
17
|
+
## Source
|
|
18
|
+
|
|
19
|
+
https://github.com/amkisko/partition_gardener.rb/issues/18
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Cut patch release 0.3.4
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
Cut patch release 0.3.4 for child column align before ATTACH PARTITION, shipped after 0.3.3.
|
|
10
|
+
|
|
11
|
+
## Effects
|
|
12
|
+
|
|
13
|
+
Moved Unreleased notes into CHANGELOG.md under 0.3.4. Bumped lib/partition_gardener/version.rb and path-gem lockfiles to 0.3.4.
|
|
14
|
+
|
|
15
|
+
## Next
|
|
16
|
+
|
|
17
|
+
Merge trunk/0.3.4 to main, then run make release.
|
|
18
|
+
|
|
19
|
+
## Source
|
|
20
|
+
|
|
21
|
+
https://github.com/amkisko/partition_gardener.rb/issues/18
|
|
22
|
+
https://github.com/amkisko/partition_gardener.rb/pull/19
|
|
23
|
+
|
|
24
|
+
Feature note: usr/docs/changelogs/20260902114500_align-child-columns-before-attach.md
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Occupied window current origin
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
Date-range planning keeps attached monthly children whose ranges overlap the active window. The remainder after a contiguous occupying prefix from the window start is named open. Current is reserved for a filler that starts at the window origin. OccupiedWindow reads Connection.attached_partitions bounds. ZoneSegments walks those catalog segments before heat splits and fillers. Monthly name parse also accepts an optional first-of-month suffix so those child names resolve as that month.
|
|
10
|
+
|
|
11
|
+
A later pass changed the remainder name from current to open so the slot matches the documented origin rule.
|
|
12
|
+
|
|
13
|
+
## Effects
|
|
14
|
+
|
|
15
|
+
A monthly catalog through the current month no longer plans a current partition that overlaps the occupying child. Postgres attach of the remainder filler starts at the next month as open.
|
|
16
|
+
|
|
17
|
+
## Source
|
|
18
|
+
|
|
19
|
+
Follows usr/docs/issues/20260909143500_occupied-window-current-origin.md. Specs: spec/partition_gardener/date_range_occupied_window_spec.rb, spec/partition_gardener/sliding_window_spec.rb, spec/integration/sliding_window_maintenance_spec.rb.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Tail slot RFC
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
RFC 0001 records the project RFC process. RFC 0002 specifies occupancy-first tail slot names. A date-named child that covers a range is that range. Current, open, and future fill only uncovered ranges. Future starts after premade months that occupy keys at or after the window end. Registry flags are out of this RFC. A later pass dropped ensure_current, ensure_future, and ensure_default from the draft.
|
|
10
|
+
|
|
11
|
+
## Effects
|
|
12
|
+
|
|
13
|
+
rfcs/0001-rfc-process.md and rfcs/0002-tail-slots.md are Proposed. Occupied-window naming (open after an occupying origin) matches RFC 0002 current-zone occupancy. A later pass put high-end occupancy for future into the planner. Registry flags are not in this RFC.
|
|
14
|
+
|
|
15
|
+
## Next
|
|
16
|
+
|
|
17
|
+
Discuss RFC 0002 unresolved questions. Implementation PRs cite RFC-0002.
|
|
18
|
+
|
|
19
|
+
## Source
|
|
20
|
+
|
|
21
|
+
Follows usr/docs/issues/20260909143500_occupied-window-current-origin.md and rfcs/0002-tail-slots.md.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# High-end occupancy for future
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
A date-named child that covers keys at or after the active window end stays in the plan. Future starts after the latest finite end among those occupants. Future is omitted when an occupant already ends at MAXVALUE. Holes between those occupants stay gaps. Default remains residual routing. No registry flags.
|
|
10
|
+
|
|
11
|
+
## Effects
|
|
12
|
+
|
|
13
|
+
The sliding-window planner keeps a premade month that begins at the window end and starts future from the next month. A child that straddles the window end pushes future to that child's end. Noncontiguous premade months past the window stay attached. Apply no longer attaches future over a month that already occupies that range.
|
|
14
|
+
|
|
15
|
+
## Next
|
|
16
|
+
|
|
17
|
+
Discuss RFC 0002 unresolved questions. Integer-window occupancy is unchanged.
|
|
18
|
+
|
|
19
|
+
## Source
|
|
20
|
+
|
|
21
|
+
Follows rfcs/0002-tail-slots.md and usr/docs/issues/20260909143500_occupied-window-current-origin.md.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Shipped contract RFCs
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
Stable RFCs 0003 through 0015 specify contracts that already ship: sliding window layout, registry JSON, plan and audit reports, archive names, retention, CLI, maintenance backends, keyset rebalance, advisory lock and run records, hot switch, child column align, integer window, and hash list composite. RFC 0001 and RFC 0002 stay Proposed. Integer occupancy stays unresolved inside RFC 0014. Registry flags for ensure slots stay out.
|
|
10
|
+
|
|
11
|
+
## Effects
|
|
12
|
+
|
|
13
|
+
rfcs/ids/0003 through rfcs/ids/0015 are claimed. Matching rfcs/NNNN-slug.md files are Stable. rfcs/README.md Current set lists them. CHANGELOG 0.3.5 records the set. Operator guides gained Related links. docs/cli.md apply --all example now includes --confirm.
|
|
14
|
+
|
|
15
|
+
## Next
|
|
16
|
+
|
|
17
|
+
Implementation PRs cite RFC-NNNN. Discuss RFC 0002 unresolved questions. Integer occupancy is a follow-on, not this set.
|
|
18
|
+
|
|
19
|
+
## Source
|
|
20
|
+
|
|
21
|
+
Follows the RFC 0002 occupancy-first work and the request to specify remaining shipped contracts under rfcs/.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Cut patch release 0.3.5
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
Cut patch release 0.3.5 on main for occupancy-first sliding-window plans and RFCs 0001 through 0015, shipped after 0.3.4. Stay on main. No trunk branch.
|
|
10
|
+
|
|
11
|
+
## Effects
|
|
12
|
+
|
|
13
|
+
Moved Unreleased notes into CHANGELOG.md under 0.3.5. Bumped lib/partition_gardener/version.rb and path-gem lockfiles to 0.3.5.
|
|
14
|
+
|
|
15
|
+
## Next
|
|
16
|
+
|
|
17
|
+
Commit the version cut, then run make release.
|
|
18
|
+
|
|
19
|
+
## Source
|
|
20
|
+
|
|
21
|
+
Occupancy: usr/docs/changelogs/20260909143500_occupied-window-current-origin.md
|
|
22
|
+
High-end future: usr/docs/changelogs/20260909162554_high-end-future-occupancy.md
|
|
23
|
+
RFC 0002: usr/docs/changelogs/20260909154900_tail-slot-rfc.md
|
|
24
|
+
Stable RFCs: usr/docs/changelogs/20260909164000_shipped-contract-rfcs.md
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Public identifiers contract
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
Host applications treat database uniqueness, public identifier, routing hint, and authorization as four contracts. When id is unique across children, keep a scalar application id and attach a routing hint on point lookups. When id is unique only inside a child, the public point-lookup identifier carries every uniqueness column as one opaque path segment.
|
|
10
|
+
|
|
11
|
+
Prefer Rails signed_id or SignedGlobalID when primary_key is the composite array. When primary_key stays :id, sign [id, partition_key] with a host MessageVerifier or use an unpartitioned mapping table. query_constraints still only helps writes. Do not use to_param underscore form or unsigned GlobalID for public point lookups. Fail closed after decode. Browse screens still show period or tenant. Gardener does not ship an encoder.
|
|
12
|
+
|
|
13
|
+
## Effects
|
|
14
|
+
|
|
15
|
+
docs/application_contract.md gained a Public identifiers section. docs/partition_landscape.md Rails application contract, routing hints, and UI surfaces point to it. README application_contract blurb names public identifiers.
|
|
16
|
+
|
|
17
|
+
## Next
|
|
18
|
+
|
|
19
|
+
No RFC unless public identifiers become a gem runtime contract.
|
|
20
|
+
|
|
21
|
+
## Source
|
|
22
|
+
|
|
23
|
+
usr/docs/issues/20260916113300_opaque-composite-public-ids.md
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Checkpoint table name
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
SqlRunRecordStore default table is partition_gardener_checkpoints. Hosts set run_record_table_name when they already own another relation. First use with the default name renames partition_gardener_runs or partition_gardener_run_records when that catalog relation exists and the default table does not.
|
|
10
|
+
|
|
11
|
+
RFC 0011 records the table, the config key, and the rename.
|
|
12
|
+
|
|
13
|
+
## Effects
|
|
14
|
+
|
|
15
|
+
lib/partition_gardener/sql_run_record_store.rb and configuration.rb. Docs in configuration, operations, and audit_reference. Specs in sql_run_record_store_spec.rb.
|
|
16
|
+
|
|
17
|
+
## Next
|
|
18
|
+
|
|
19
|
+
Hosts that already created partition_gardener_run_records keep resume rows after the first enabled run, or set run_record_table_name to keep the old name.
|
|
20
|
+
|
|
21
|
+
## Source
|
|
22
|
+
|
|
23
|
+
RFC 0011
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Cut patch release 0.3.6
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
Cut patch release 0.3.6 on main for the default checkpoint table name, `run_record_table_name`, leftover table rename, and public identifier docs, shipped after 0.3.5. Stay on main. No trunk branch.
|
|
10
|
+
|
|
11
|
+
## Effects
|
|
12
|
+
|
|
13
|
+
Moved Unreleased notes into CHANGELOG.md under 0.3.6. Bumped lib/partition_gardener/version.rb and path-gem lockfiles to 0.3.6.
|
|
14
|
+
|
|
15
|
+
## Next
|
|
16
|
+
|
|
17
|
+
Run make release.
|
|
18
|
+
|
|
19
|
+
## Source
|
|
20
|
+
|
|
21
|
+
Checkpoint table: docs/changelogs/20261005135700_checkpoint-table-name.md
|
|
22
|
+
Public identifiers: docs/changelogs/20260916144600_public-identifiers-contract.md
|
|
23
|
+
RFC 0011
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Cut patch release 0.3.7
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
- Bump `PartitionGardener::VERSION` to `0.3.7`.
|
|
10
|
+
- Record user-visible correctness and contract fixes in `CHANGELOG.md` under `## 0.3.7 (2026-10-29)`.
|
|
11
|
+
|
|
12
|
+
## Effects
|
|
13
|
+
|
|
14
|
+
- Resume, hot-switch, gap detection, calendar leap day, retention notify, and integer-window JSON registry fixes landed on `patch/engineering-audit-0-3-7`.
|
|
15
|
+
- Release script now uses `git status --porcelain` and loads `PartitionGardener::VERSION` directly.
|
|
16
|
+
|
|
17
|
+
## Next
|
|
18
|
+
|
|
19
|
+
- Commit the prepared tree on `main`, tag `0.3.7`, push, and run `make release` (gem push, tag push, GitHub release). See `docs/reviews/20261029150855_engineering-audit-release-preparation.md`.
|
|
20
|
+
|
|
21
|
+
## Source
|
|
22
|
+
|
|
23
|
+
- Review: `docs/reviews/20261021220000_engineering-audit-0-3-7.md`
|
|
24
|
+
- `CHANGELOG.md`, `lib/partition_gardener/version.rb`
|
data/docs/configuration.md
CHANGED
|
@@ -47,6 +47,8 @@ When the gem loads inside Rails, the railtie sets `connection_resolver` and `tod
|
|
|
47
47
|
|
|
48
48
|
`run_record_enabled` (default: `true`) — persist phase checkpoints for resume (global default).
|
|
49
49
|
|
|
50
|
+
`run_record_table_name` (default: `partition_gardener_checkpoints`) — PostgreSQL table used by `SqlRunRecordStore`. On first use with the default name, the store renames `partition_gardener_runs` or `partition_gardener_run_records` when that relation exists and the default table does not.
|
|
51
|
+
|
|
50
52
|
`run_record_store` (default: `SqlRunRecordStore` when a database connection is available, else in-memory) — where rebalance checkpoints are stored.
|
|
51
53
|
|
|
52
54
|
`strict_maintenance_backend_validation` (default: `false`) — when `true`, raise `MaintenanceBackend::ValidationError` on register if `maintenance_backend` disagrees with `partman.parent_config`; when `false`, notify only.
|
|
@@ -67,7 +69,7 @@ Do not run two full `run!` jobs against the same table concurrently. Host apps s
|
|
|
67
69
|
|
|
68
70
|
### Run records
|
|
69
71
|
|
|
70
|
-
When a database connection is configured (Active Record or `DATABASE_URL`), `SqlRunRecordStore` creates `
|
|
72
|
+
When a database connection is configured (Active Record or `DATABASE_URL`), `SqlRunRecordStore` creates `partition_gardener_checkpoints` on first use. Checkpoints let incremental rebalance resume after partial failure. Disable with `config.run_record_enabled = false` or per-table `run_record_enabled: false`. Set `config.run_record_table_name` when the host already owns another table name.
|
|
71
73
|
|
|
72
74
|
## Per-table registration
|
|
73
75
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# json CVE-2026-71847
|
|
2
|
+
|
|
3
|
+
## Dependency
|
|
4
|
+
|
|
5
|
+
json, pulled in through the development graph (rubocop / activesupport). Root Gemfile.lock already had 2.21.2 after the Dependabot bundler group bump. Appraisal locks gemfiles/rails72.gemfile.lock, gemfiles/rails8ruby34.gemfile.lock, and gemfiles/rails8ruby4.gemfile.lock still resolved 2.20.0.
|
|
6
|
+
|
|
7
|
+
## Symptom
|
|
8
|
+
|
|
9
|
+
bundle-audit check reports GHSA-9hj4-r449-hfvc / CVE-2026-71847 on json 2.20.0 through 2.21.1. The published fix is >= 2.21.2. Dependency audit CI on the 0.3.3 merge failed against the root lock while it still had 2.21.1. After Dependabot updated only Gemfile.lock, later audit jobs on main passed while the appraisal graphs CI actually installs stayed on 2.20.0. The audit workflow find matched files named Gemfile.lock only, so gemfiles/*.gemfile.lock were never scanned.
|
|
10
|
+
|
|
11
|
+
Test CI on those same appraisal locks also failed in frozen mode because they still listed partition_gardener 0.3.2 after VERSION moved to 0.3.3.
|
|
12
|
+
|
|
13
|
+
## Evidence
|
|
14
|
+
|
|
15
|
+
Local bundle-audit check --gemfile-lock on each appraisal lock reported json 2.20.0 and the advisory. GitHub advisory: https://github.com/advisories/GHSA-9hj4-r449-hfvc. Upstream advisory: https://github.com/ruby/json/security/advisories/GHSA-9hj4-r449-hfvc. Failed Dependency audit run on the 0.3.3 merge: GitHub Actions run 31696494175.
|
|
16
|
+
|
|
17
|
+
## Suggested fix
|
|
18
|
+
|
|
19
|
+
Relock the three appraisal gemfiles so json is 2.21.2 and the path gem is 0.3.3. Teach .github/workflows/dependency-audit.yml to scan both Gemfile.lock and *.gemfile.lock.
|
|
20
|
+
|
|
21
|
+
## Next
|
|
22
|
+
|
|
23
|
+
Land the relock on main. Dependabot still watches only the root bundler directory, so appraisal graphs will need a manual relock when the next advisory lands unless that config grows.
|
|
24
|
+
|
|
25
|
+
## Source
|
|
26
|
+
|
|
27
|
+
Upstream: https://github.com/advisories/GHSA-9hj4-r449-hfvc and CVE-2026-71847. Downstream: gemfiles/*.gemfile.lock and .github/workflows/dependency-audit.yml on patch/relock-appraisal-advisory-json.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Occupied monthly children at the active window start
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
When attached monthly children already cover the start of the sliding-window active range, the plan keeps those children and fills the remainder as open, not current. Current is only the filler that starts at the active window origin. The planner reads occupancy from attached range bounds, not only from parsed monthly names.
|
|
10
|
+
|
|
11
|
+
Archive children whose range ends at or before the window start stay archive. Tail slot names current, open, and future are not occupancy. A first-month heat split that is not yet attached already named the later filler open; occupied prefix uses the same name.
|
|
12
|
+
|
|
13
|
+
RFC 0002 records occupancy-first placement. A date-named child that covers a range is that range. Current, open, and future fill only uncovered ranges. Default is residual routing. This patch does not add registry flags. A later RFC 0002 pass dropped ensure flags from the draft and added high-end occupancy for future versus premade months past the window.
|
|
14
|
+
|
|
15
|
+
## Effects
|
|
16
|
+
|
|
17
|
+
A catalog of monthly children through the current month, with default only and no current or future slot, plans open from the next month and attaches without overlapping an existing child. A premade month that begins at the window end stays attached. Future starts after that month.
|
|
18
|
+
|
|
19
|
+
## Next
|
|
20
|
+
|
|
21
|
+
RFC 0002 stays Proposed. Unresolved questions live in the RFC, including integer occupancy. Implementation PRs cite RFC-0002.
|
|
22
|
+
|
|
23
|
+
## Source
|
|
24
|
+
|
|
25
|
+
Requested as a sliding-window plan fix after 0.3.3 skipped only the reverse overlap, archive attach when current already covers that month. Naming follow-up: current must not start after the occupying prefix.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Specify shipped contracts as Stable RFCs
|
|
2
|
+
|
|
3
|
+
## Participants
|
|
4
|
+
|
|
5
|
+
Andrei Makarov (@amkisko)
|
|
6
|
+
|
|
7
|
+
## Decisions
|
|
8
|
+
|
|
9
|
+
Write Standards Track Stable RFCs for every shipped contract named in the RFC gap analysis, including layouts and execution paths that were previously operator-guide only. Skip whether-to-partition advice, engine recipes, monitoring SLOs, host CI, job wiring, and landscape UI notes. Skip registry ensure flags. Occupancy for integer catalogs stays an unresolved question, not a claimed walk.
|
|
10
|
+
|
|
11
|
+
RFC numbers: 0003 sliding-window-layout, 0004 registry-json, 0005 plan-audit-reports, 0006 archive-naming, 0007 retention, 0008 cli, 0009 maintenance-backends, 0010 keyset-rebalance, 0011 advisory-lock-run-records, 0012 hot-switch, 0013 child-column-align, 0014 integer-window, 0015 hash-list-composite.
|
|
12
|
+
|
|
13
|
+
Facts preserved: current is origin filler, not this month. Default is always created except hash. Apply always needs --confirm. Moves are insert then delete with ON CONFLICT. partition_key_column is trusted operator SQL.
|
|
14
|
+
|
|
15
|
+
## Effects
|
|
16
|
+
|
|
17
|
+
The RFC files and id claims exist on this branch. Indexes and Related links point at the set.
|
|
18
|
+
|
|
19
|
+
## Next
|
|
20
|
+
|
|
21
|
+
Review Proposed RFC 0002. Follow-on RFC if integer occupancy ships.
|
|
22
|
+
|
|
23
|
+
## Source
|
|
24
|
+
|
|
25
|
+
Requested after RFC 0001 and RFC 0002. Related usr/docs/changelogs/20260909164000_shipped-contract-rfcs.md.
|