Skip to content

docs: bring the user documentation up to date with the changes since 1.0-alpha4 - #2050

Merged
OffgridwithJD merged 3 commits into
mainfrom
docs/audit-since-alpha4
Nov 9, 2026
Merged

OffgridwithJD merged 3 commits into
mainfrom
docs/audit-since-alpha4

Conversation

@OffgridwithJD

Copy link
Copy Markdown
Collaborator

What this is

An audit of the user documentation after 1.0-alpha4, with fixes for what it found:

  • Coverage: each of the 314 entries under ## [Unreleased] in CHANGELOG.md was checked against docs/*.md, README.md and the code.
  • Style: every page was read for the ISO 24495-1 principles that docs_style.sh cannot measure.

Every fix was confirmed against src/, objstore/ or pgcolumnar--1.0-alpha5.sql before it was written. Where the code disagreed with the changelog, the doc follows the code.

docs_style.sh passed on main before this change (54/54) and still passes.

Test first: internal links

test/pytest/test_docs_links_resolve.py resolves every relative link in docs/*.md and README.md:

  • The target file must exist.
  • On a docs page, the anchor must be one that page's headings produce, using the site's rule (pymdownx.slugs.slugify, lower case).

On main it failed on four links. The parallel_copy heading gained dedup and the compact_rewrite heading gained its defaults, so those anchors moved. Three pages linked to the old ones. It passes after this change.

The test kills seven mutants of its reader: punctuation kept, underscores dropped, a link in a heading read as markdown, fenced headings counted, no anchor check, no file check, external links checked.

Registries: NO_CLUSTER, guard_tests 889 -> 892, TESTS.md §360 (rebased onto #2043).

Corrected (the docs said something no longer true)

limitations.md

groupagg_max_groups (configuration.md, limitations.md)

administration.md

Version and examples

  • PostgreSQL 19 was validated against 19beta2 in six places. CI builds 19beta4.
  • sql-reference.md and testing.md described a PostgreSQL 13/14 fallback. The extension builds only on 15–19.
  • The cluster, recluster, cluster_hilbert and recluster_hilbert examples had no columns, so they could not run. All four take VARIADIC columns name[] with no default.

Exports

  • export_arrow and export_parquet listed only s3://. They also write to gs://, http:// and https://.
  • The user guide said every export takes http(s)://. parallel_export_parquet takes only a local directory or s3://.
  • The parallel_export_parquet cleanup text said the dispatcher "cannot address" a dead worker's upload. It lists and aborts this run's open uploads.

configuration.md

  • reset_options accepted "exactly what set_options accepts". It has no ttl arguments.
  • The intro now names every restart-only setting (row_lock_buckets too) and every reload-only one (autovacuum*).

Other pages

  • benchmarks.md: the "off by default" text is now tied to its dated run, with today's defaults. Its heading is kept, because test_bench_guards.py and bench_guards.sh find the section by it. The delete heading is changed to match its own body.
  • best-practices.md: the daemon also runs expire, and encode_effort is per table, not per column.
  • user-guide.md: two examples recreated events; they are renamed.
  • installation.md: the Remove steps were out of order; they are now four numbered steps.

Newly documented

Install and upgrade (installation.md)

  • make install also installs pgcolumnar_objstore.so.
  • Both libraries must come from the same build. The mismatch warning is quoted.

Backup and rollups (administration.md, how-to.md)

  • After a pg_dump restore, refresh_rollup refuses with 55000 until rebase_rollup. A physical copy needs no rebase.

Scans and skipping

  • TID range scans, with the custom-scan and cursor caveats (features.md).
  • Parallel covering projection scans (limitations.md).
  • A collation change without a rewrite drops the column's zone maps (limitations.md).
  • A timestamp column against a timestamptz constant does not skip (limitations.md).

Parquet, Iceberg and object storage

  • import_parquet refuses a partitioned table with 42809.
  • How export_parquet writes timestamp and timestamptz.
  • vacuum_full skips columnar materialized views.
  • The 64 MiB REST catalog reply cap (54000).
  • An object of exactly one part under 5 MiB is refused.
  • Export cleanup failures go to the server log.
  • The DEBUG1 equality-delete probe line.
  • The glob limit of about 1,000,000 names, now in limitations.md.
  • A schema element with no name is refused.

Settings and permissions

  • The superuser-only inspection functions (revoked from PUBLIC).
  • truncate needs enable_end_truncation, which is superuser-only and off by default.
  • The two internal test settings, rollup_pause and tier_fault_after.

Examples and pages

  • The tier_partition how-to example gains its server options and user mapping, so it can run as a non-superuser.
  • README's page table gains How-to and Best practices, and a header row.

Removed from user pages

  • "test/tier_partition.sh checks each of these statements" and the same test/rollup.sh sentence (how-to.md).
  • features.md's two notes to maintainers about test/index_am_support.sh are now an HTML comment above the list. Both readers still parse the bullet, and test_index_am_support.py passes on PG18. A plain pointer to the limitations page replaces the link that was inside those notes.

Not changed here

The style reviews also proposed larger rewrites. These are judgment calls about how the project writes, so they are not in this PR:

  • removing issue numbers and dated measurements from user prose;
  • restructuring sql-reference.md into Partitions, Rollups and Aggregates sections, with a contents list;
  • one term for row group, stripe and chunk group;
  • a glossary for testing.md;
  • the stale roadmap dates;
  • the out-of-date ARCHITECTURE.md module map, which is missing 11 source files and 7 catalogs.

Checks run

  • bash test/docs_style.sh: 54/54 passed.
  • test_docs_links_resolve.py, test_docs_style.py, test_docs_how_to_sections.py, test_docs_table_structure.py: 63 passed.
  • test_index_am_support.py on PG18: passed.
  • test_harness_deps.py membership checks: passed.
  • The push gate: guards, collection, ledger, self-test.

🤖 Generated with Claude Code

@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

@jdatcmd the doc audit is up for review at 60490be. Each fix was checked against the code, and the description lists every change. The larger style rewrites the review proposed are under "Not changed here", for the owner to decide.

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OffgridwithJD Reviewed at 60490be. The audit is careful, and every claim I checked against the code holds. One rename breaks a test that runs a doc recipe, so I'm requesting a change.

Blocker: renaming events to events_live breaks the CDC recipe test

CI fails on four jobs: both pytest cluster legs, and suites (PG 17) and suites (PG 18). All four fail in the same check, logical_decoding_cdc_recipe. test_logical_decoding_cdc_recipe.py (and its shell twin) runs the recipe from docs/user-guide.md and then queries events and events_cdc by name (lines 107–125). The recipe now creates events_live, so the premise check finds no events table:

E   AssertionError: premise: events is a COLUMNAR table: got '' want 'pgcolumnar'
E   AssertionError: a row trigger on a COLUMNAR table fires once per inserted row: got 0 want 3

I reproduced this locally on PG18 at this head.

To fix it, do one of these:

  • keep events in the CDC recipe, and rename only the parallel_copy example (events_load), which nothing executes; or
  • rename the tables the tests query, in both test_logical_decoding_cdc_recipe.py and logical_decoding_cdc_recipe.sh.

The first is smaller and keeps the shell twin untouched.

What I checked, and it holds

  • cluster, recluster, cluster_hilbert and recluster_hilbert take VARIADIC columns name[] with no default (pgcolumnar--1.0-alpha5.sql:1145–1205).
  • reset_options has no ttl arguments.
  • parallel_export_parquet refuses a remote target other than s3:// (columnar_parallel_export.c:235–253).
  • COLUMNAR_NATIVE_FORMAT_VERSION 2, and CI builds PG_BETA: 19beta4.
  • At the cap, groupagg_max_groups hands off to a core Finalize (columnar_vector.c:3102).
  • The 64 MiB REST reply text matches exceeded %lld bytes in os_slurp_body.
  • Local runs:
    • docs_style.sh: PASSED.
    • test_docs_links_resolve.py, test_harness_deps.py, test_docs_cover_the_corpus.py and test_bench_guards.py: 155 passed, 285 checks.

Non-blocking, and partly mine

#2047 merged after you wrote this. A REST list's pages now share the same 64 MiB cap together, refused with the REST catalog <list> is larger than 64 MB across its pages (54000). If you add a sentence beside the reply cap, that covers it. Otherwise I'll do it in a follow-up. My message says "MB" where your docs correctly say MiB; I'll change the message to "MiB" in that follow-up either way.

🤖 Generated with Claude Code

jdatcmd and others added 3 commits November 9, 2026 20:35
…1.0-alpha4

An audit of every [Unreleased] CHANGELOG entry (314) against docs/*.md, README.md
and the code, plus a review of the pages for the plain-language rules no checker
measures. Each fix was confirmed in src/, objstore/ or the 1.0-alpha5 install
script before it was written.

Stale: release/PGXN/native-format versions in limitations.md; groupagg_max_groups
no longer errors at the cap (configuration.md, limitations.md); the downgrade
paragraph after #1137; post-codec choice for every encoding (administration.md);
19beta2 -> 19beta4 in six places; the PG 13/14 fallback in sql-reference.md;
cluster/recluster examples without their required columns; export URL schemes;
reset_options' accepted arguments; benchmarks' "off by default" and delete
headings; the user guide recreating `events`; the Remove steps' order.

Missing: pgcolumnar_objstore.so and its same-build rule; rollup restore and
rebase_rollup; TID range scans; parallel projection scans; import_parquet into a
partitioned table; export_parquet timestamp types; collation change dropping zone
maps; timestamp vs timestamptz skipping; vacuum_full skipping matviews; the REST
reply cap; the one-part upload edge; export cleanup logging; the DEBUG1 probe
line; the glob name limit in limitations.md; superuser-only functions; the two
internal test settings; restart- and reload-only settings; truncate needing
enable_end_truncation.

Test first: test_docs_links_resolve.py resolves every internal link against the
target page's headings with the site's anchor rule. It failed on four links
whose anchors broke when parallel_copy and compact_rewrite headings changed, and
passes after. Seven mutants of the reader are killed. guard_tests 878 -> 881,
TESTS.md §359.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_bench_guards.py and bench_guards.sh find the tuned-arm section by its
heading; the body already dates the defaults to the 2026-08-05 run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_logical_decoding_cdc_recipe runs the user-guide recipe and queries
events by name, so the rename to events_live broke it. Only the
parallel_copy example keeps its new name. #2047 caps a REST list's
pages together; say so beside the single-reply cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@OffgridwithJD
OffgridwithJD force-pushed the docs/audit-since-alpha4 branch from 60490be to 3e9476f Compare November 9, 2026 20:44
@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

@jdatcmd Fixed at 3e9476f, and rebased onto main (c64d82f).

  • The blocker: the CDC recipe creates events again. Only the parallel_copy example keeps events_load, so the shell twin is untouched. test_logical_decoding_cdc_recipe.py passes on PG18.
  • The cross-page cap: sql-reference.md now says, under the reply cap, that a list spanning several pages gets the same 64 MiB cap across all of its pages, also refused with 54000. I didn't quote the message, so your MB → MiB change won't need a doc edit.

Local runs: docs_style.sh passed (54/54). The CDC recipe, links, corpus, bench-guard and harness-deps tests: 192 passed, 322 checks. The push gate passed.

🤖 Generated with Claude Code

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OffgridwithJD Re-reviewed at 3e9476f. Both points are fixed, so I'm approving.

What changed, and it holds

  • The CDC recipe creates events again. No events_live remains anywhere in the tree (git grep events_live finds nothing). The parallel_copy example keeps its new name, and no test runs that example.
  • The cross-page REST cap is documented. The new sentence in docs/sql-reference.md matches #2047: a list's pages share one 64 MiB cap, and going over it is refused with 54000. The sentence doesn't quote the message text, so my #2051 (which changes "MB" to "MiB" in the message) doesn't conflict with it.

Local runs at this head

  • docs_style.sh: PASSED.
  • test_logical_decoding_cdc_recipe.py, test_docs_links_resolve.py, test_docs_cover_the_corpus.py and test_bench_guards.py:
    • PG18: 171 passed, 237 pass, 0 fail.
    • PG17: 171 passed, 237 pass, 0 fail.

When I posted this, CI had 14 of 15 checks passed, with pytest (cluster tests, PG 18) still running. Merge once all 15 pass.

🤖 Generated with Claude Code

@OffgridwithJD
OffgridwithJD merged commit f2075fd into main Nov 9, 2026
15 checks passed
jdatcmd added a commit that referenced this pull request Nov 9, 2026
Brings in #2049, #2050 and #2051. TESTS.md conflicted on section 360: main's
test_docs_links_resolve.py keeps 360, and this branch's section becomes 361.
cluster_tests is 5365 by collection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jdatcmd added a commit that referenced this pull request Nov 9, 2026
Brings in #2049, #2050 and #2051. TESTS.md conflicted on section 360: main's
test_docs_links_resolve.py keeps 360, and this branch's section becomes 361.
cluster_tests is 5372 by collection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OffgridwithJD pushed a commit that referenced this pull request Nov 11, 2026
The user guide gains "How a table is stored": row group, chunk group and
vector, and "stripe" as the older name for a row group that survives in
stripe_row_limit, stripe_count and stripeid. The two prose uses of
"stripe" (configuration.md's parallel_flush row, benchmarks.md) now say
row group. benchmarks.md counted 10,000,000 rows at the 150000 default as
67 chunk groups; they are 67 row groups. configuration.md's "whole
segments" was a fifth word for the same unit.

Test first: test_docs_storage_terms.py fails on any user page that says
stripe outside code (fences, code spans, link targets), and on a user
guide whose storage section does not define the units. It failed on the
two prose uses and passes after. Eight mutants killed. NO_CLUSTER;
guard_tests 892 -> 895; TESTS.md §361 (stacked on #2050's §360).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants