Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ REPO_READY_AUDIT.md

# MkDocs build output
site/
.venv-docs/

# pg_regress expected outputs — tracked; the global *.out would exclude them.
!extension/coldfront/test/expected/*.out
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Snapshots of upstream state for the next major moves. Re-verify before acting on
- duckdb-iceberg's 2.0-line commit path is rewritten (a retry loop with `RefreshFromCatalog` firing reactively after a 409, rather than proactively before the first attempt). Our bakery patch's anchors (`RefreshExistingManifestList`, `GetTransactionRequest`) no longer exist there — the proactive pre-commit refresh needs reimplementing, not dropping.
- Two of our interop patches (manifest-list `format-version`, lowercase parquet `file_format`) are still needed against the 2.0-line `main`.
- The DuckDB temp-spill collision above (`duckdb#15173`, `pg_duckdb#887`) is fixed on the 2.0 line: spill files are instance-qualified, so the per-backend temp directory stops being a correctness requirement once the stack moves to 2.0.
- Partitioned `INSERT` and `CREATE TABLE ... PARTITIONED BY (...)` already work at our current `ICEBERG_REF`; `docs/architecture.md` and the extension's partition-column notice calling this unsupported are stale and should be corrected independently of the 2.0 move.
- Partitioned `INSERT` and `CREATE TABLE ... PARTITIONED BY (...)` already work at our current `ICEBERG_REF`; `docs/architecture_guides/index.md` and the extension's partition-column notice calling this unsupported are stale and should be corrected independently of the 2.0 move.

**DuckDB 1.5.6 (`v1.5-variegata` repin)** (checked 2026-10-04 at head `5dcf5070`): moving to the branch head forces a DuckDB newer than 1.5.4 for the whole stack — pg_duckdb loads extensions only for its exact DuckDB version, and pg_duckdb PR #1071 bumps to 1.5.5 while nothing upstream has tried 1.5.6 yet. All five `docker/iceberg-*-v15.patch` files still apply cleanly at the head and none of their fixes have landed upstream; `referenced_data_file` is still reader-only and `RETURNING` on a cold `INSERT`/`UPDATE`/`DELETE`/`MERGE` is still refused. The gains are vended-credential refresh, equality-delete scans with extra columns, truncated UTF-8 string bounds, an Azure SAS endpoint-suffix fix, and a `write.metadata.metrics` backport — treat a repin as a DuckDB stack move (base republish, full matrix), not a quick ref bump.

Expand All @@ -99,8 +99,8 @@ Snapshots of upstream state for the next major moves. Re-verify before acting on
## Documentation
- User docs live in `docs/` as a MkDocs site (pgEdge MkDocs structure); `README.md` is the GitHub landing/TOC. Build with `mkdocs build --strict` — it must pass with no warnings.
- Keep `README.md` and `docs/index.md` near-identical, EXCEPT `docs/index.md` is user-facing and omits the developer-specific content that belongs only in a GitHub README: CI badges, build-from-source internals, the project-structure tree, dependency/build tables, and author/contributor info.
- Three indexes point at the pages in `docs/`, each with its own focus: the `mkdocs.yml` `nav:` (everything, including changelog, license and `formal/`), the `README.md` Documentation table (one terse row per guide), and the `docs/index.md` Next Steps list (prose, user-facing, top-level guides only; the per-mode deep dives are reached through `docs/architecture.md`, which lists them). Adding, renaming, or removing a guide under `docs/` means updating all three in the same commit; adding a deep dive means the nav, the README table, and the list in `docs/architecture.md`. `mkdocs build --strict` passes on a page no index links, so it will not catch this: check by listing `docs/*.md` against each index.
- Three indexes point at the pages in `docs/`, each with its own focus: the `mkdocs.yml` `nav:` (everything, including changelog, license and `formal/`), the `README.md` Documentation table (one terse row per guide), and the `docs/index.md` Next Steps list (prose, user-facing, top-level guides only; the per-mode deep dives are reached through `docs/architecture_guides/index.md`, which lists them). Adding, renaming, or removing a guide under `docs/` means updating all three in the same commit; adding a deep dive means the nav, the README table, and the list in `docs/architecture_guides/index.md`. `mkdocs build --strict` passes on a page no index links, so it will not catch this: check by listing `docs/*.md` against each index.
- Internal/scratch docs (bench, experimental, hardening, comparison, backlog, scale-test, E2E) are gitignored and NEVER pushed to GitHub; never reference them from published docs.
- ARCHITECTURE docs are reference material, not work logs: brief, present-tense, no history ("we used to…", version churn), no rejected-alternative narration. Keep the *why* (rationale that explains the design); cut the journey.
- One home per topic, no duplication across docs: usage/modes/config/CLI and one-time setup in `docs/usage.md`; build-from-source and testing/CI in `docs/installation.md`; storage-backend setup in `docs/object_store.md`; deep dives in `docs/architecture*.md`. When moving a section, fix every cross-anchor that pointed at it.
- One home per topic, no duplication across docs: shared day-to-day usage and the partition CLI in `docs/using_coldfront/index.md`; each mode's own guide in `docs/usage_tiered.md`, `docs/usage_decoupled.md`, and `docs/usage_partitioner.md`; PostgreSQL/ColdFront config in `docs/configuration.md`; Lakekeeper install/config/bootstrap in `docs/one_time_setup.md`; build-from-source and testing/CI in `docs/installation.md`; storage-backend setup in `docs/object_store.md`; deep dives in `docs/architecture_guides/index.md` and `docs/architecture_tiered.md`/`docs/architecture_decoupled.md`/`docs/architecture_vectors.md`. When moving a section, fix every cross-anchor that pointed at it.
- Tracked build-journal docs (`DUCKDB_1.5_PATCHED.md`, `DUCKDB_1.5_UNPATCHED.md`) are kept as history and never deleted, but they are not part of the docs site: never link them from `README.md` or `docs/`. Point build internals at the real recipe, `docker/Dockerfile.duckdb15-base`.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Thanks for your interest in improving ColdFront.
## Getting started

- Build and run the stack: [Installation](docs/installation.md).
- Day-to-day usage and the two operating modes: [Usage](docs/usage.md).
- Architecture: [Architecture](docs/architecture.md) (plus the tiered/decoupled
- Day-to-day usage and the two operating modes: [Usage](docs/using_coldfront/index.md).
- Architecture: [Architecture](docs/architecture_guides/index.md) (plus the tiered/decoupled
deep dives).

## Development workflow
Expand Down
60 changes: 38 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ The ColdFront documentation consists of the following guides:
- [Building ColdFront from Source](docs/installation.md)
- [Setting Up an Object Store](docs/object_store.md)
- Architecture
- [Architecture Overview](docs/architecture.md)
- [Architecture Overview](docs/architecture_guides/index.md)
- [Tiered Mode](docs/architecture_tiered.md)
- [Decoupled Mode](docs/architecture_decoupled.md)
- [Vector Storage](docs/architecture_vectors.md)
- [Using ColdFront](docs/usage.md)
- [Using ColdFront](docs/using_coldfront/index.md)
- [Storing and Searching Embeddings](docs/usage_vectors.md)
- [Compacting the Cold Tier](docs/compaction.md)
- Developer Resources
Expand Down Expand Up @@ -133,9 +133,10 @@ settings above. The `import` command takes a deployment YAML, modeled on
[config.example.yaml](config.example.yaml), and writes it into the server once.
ColdFront has no configuration file. A YAML passed to any later run is checked
against the server, and the run takes only `postgres.dsn` from the file.
For every setting, see the [One-Time Setup](docs/usage.md#one-time-setup) and
[Tuning Knobs](docs/usage.md#tuning-knobs) sections of the Using ColdFront
guide.
For every setting, see the
[Configuring Lakekeeper](docs/one_time_setup.md) guide and the
[Configuring PostgreSQL](docs/configuration.md#configuring-postgresql)
section of the Configuring ColdFront guide.

## Quickstart

Expand All @@ -147,7 +148,7 @@ docker compose --profile local-store up -d --build
```

Bootstrap Lakekeeper and create a warehouse (see the one-time setup in the
[Using ColdFront](docs/usage.md) guide), then create a table in psql:
[Using ColdFront](docs/using_coldfront/index.md) guide), then create a table in psql:

```sql
CREATE EXTENSION IF NOT EXISTS pg_duckdb;
Expand All @@ -167,28 +168,33 @@ than creating it: `coldfront.adopt_iceberg_table()` reads its schema from the
catalog and gives it the same wrapper view and registry row, read-only unless
you pass `p_writable => true`. `coldfront.release_iceberg_table()` hands the
table back with the Iceberg table untouched. See
[Adopting a Table That Already Exists in the Catalog](docs/usage.md#adopting-a-table-that-already-exists-in-the-catalog).
[Adopting a Table That Already Exists in the Catalog](docs/usage_decoupled.md#adopting-a-table-that-already-exists-in-the-catalog).

To remove a table again, `coldfront.drop_iceberg_table()` unregisters it and
drops the Iceberg table, deleting the stored objects only when asked to. See
[Dropping an Iceberg Table](docs/usage.md#dropping-an-iceberg-table-both-modes).
[Dropping an Iceberg Table](docs/usage_decoupled.md#dropping-an-iceberg-table-both-modes).

For compliance environments that cannot store an object-store credential,
`coldfront.set_storage_secret_vended()` runs with no credential in the
database: Lakekeeper issues short-lived per-table credentials at access time.
See [Vended Credentials](docs/usage.md#vended-credentials).
See [Vended Credentials](docs/vended_credentials.md).

## Using ColdFront

The Quickstart covers a decoupled table from start to finish. The
[Using ColdFront](docs/usage.md) guide covers both modes in depth, the
standalone partition manager and its CLI, the storage backends, and the
distributed setup; the [walkthrough](docs/walkthrough.md) demos run each mode
on a sample table.
The Quickstart walks through a decoupled table from start to finish.
[Using ColdFront in Tiered Mode](docs/usage_tiered.md),
[Using ColdFront in Decoupled Mode](docs/usage_decoupled.md), and
[Using ColdFront in Standalone Partitioned Mode](docs/usage_partitioner.md)
document each mode in depth; the [Using ColdFront](docs/using_coldfront/index.md) guide
helps you pick one, and the [walkthrough](docs/walkthrough.md) demos run
each mode on a sample table. Operational topics shared across modes -
caveats, vended credentials, reading and writing, supported types, and
distributed (mesh) setup - are documented under Administration.

## Documentation

The following table lists the ColdFront guides and what each one covers:
The following table lists the ColdFront guides and what each one
documents:

| Doc | Contents |
|---|---|
Expand All @@ -197,12 +203,22 @@ The following table lists the ColdFront guides and what each one covers:
| [Decoupled mode demo](docs/walkthrough_decoupled.md) | Stores a table in Iceberg from the first row and adopts a table that another engine wrote. |
| [Partitioner demo](docs/walkthrough_partitioner.md) | Manages PostgreSQL range partitions without any cold tier. |
| [Distributed demo](docs/walkthrough_distributed.md) | Points two PostgreSQL nodes at one shared lake. |
| [Embeddings](docs/usage_vectors.md) | Covers storing and searching embeddings with the pgvector interface. |
| [Usage](docs/usage.md) | Covers day-to-day use: both modes plus the standalone partition manager, one-time setup, reading and writing, supported types, the partition CLI, storage backends, distributed (mesh) setup, and tuning. |
| [Installation](docs/installation.md) | Covers building from source (Docker or bare-metal), and testing and CI. |
| [Configuring your Object Store](docs/object_store.md) | Gets ColdFront running on cloud S3 (virtual-hosted), end to end. |
| [Compaction](docs/compaction.md) | Covers cold-tier table maintenance: compaction, snapshot expiry, and orphan-file removal. |
| [Architecture](docs/architecture.md) | Describes the shared architecture and core mechanics. |
| [Embeddings](docs/usage_vectors.md) | Documents storing and searching embeddings with the pgvector interface. |
| [Usage](docs/using_coldfront/index.md) | Compares the three operating modes and links to each mode's guide. |
| [Tiered mode usage](docs/usage_tiered.md) | Documents archiving aging partitions to Iceberg while recent rows stay in the PostgreSQL heap. |
| [Decoupled mode usage](docs/usage_decoupled.md) | Documents tables that live entirely in Iceberg from the first row, and dropping or releasing a registered table. |
| [Standalone partitioner usage](docs/usage_partitioner.md) | Documents managing PostgreSQL partitions with no cold tier at all, and the partition CLI shared with tiered mode. |
| [Caveats](docs/caveats.md) | Documents cross-tier isolation, mixed transactions, and other sharp edges shared between tiered and decoupled tables. |
| [Vended Credentials](docs/vended_credentials.md) | Documents running with no stored object-store credential, for AWS S3 and Azure ADLS Gen2. |
| [Reading and Writing](docs/reading_writing.md) | Documents the SQL surface shared between tiered and decoupled tables. |
| [Supported Column Types](docs/supported_types.md) | Documents the PostgreSQL column types, including arrays, that a cold tier supports. |
| [Distributed Setup](docs/distributed_setup.md) | Documents running a multi-writer decoupled-mode Spock mesh against one shared lake. |
| [Installation](docs/installation.md) | Documents installing from a package or building from source (Docker or bare-metal), and testing and CI. |
| [Configuring ColdFront](docs/configuration.md) | Documents configuring PostgreSQL and ColdFront's own configuration. |
| [Configuring Lakekeeper](docs/one_time_setup.md) | Installs, configures, and bootstraps Lakekeeper, then installs the extensions each database needs. |
| [Configuring your Object Store](docs/object_store.md) | Gets ColdFront running end to end, for any of four supported backends: S3-compatible, virtual-hosted cloud S3, GCS, or Azure ADLS Gen2. |
| [Compaction](docs/compaction.md) | Documents cold-tier table maintenance: compaction, snapshot expiry, and orphan-file removal. |
| [Architecture](docs/architecture_guides/index.md) | Describes the shared architecture and core mechanics. |
| [Architecture: tiered](docs/architecture_tiered.md) | Describes tiered mode (hot PG plus cold Iceberg) in depth. |
| [Architecture: decoupled](docs/architecture_decoupled.md) | Describes decoupled (iceberg-only) mode in depth. |
| [Architecture: vectors](docs/architecture_vectors.md) | Describes vector storage internals: type mapping, routing state, cluster assignment, and layout. |
Expand Down Expand Up @@ -239,7 +255,7 @@ For how the non-superuser path works - the `SECURITY DEFINER` attach helpers,
the `PGC_SUSET` / `GUC_SUPERUSER_ONLY` config hardening, the
`duckdb.postgres_role` default that the image sets up, and how least privilege
holds across a Spock mesh - see
[Architecture: non-superuser app roles](docs/architecture.md#non-superuser-app-roles-least-privilege).
[Architecture: non-superuser app roles](docs/architecture_guides/index.md#non-superuser-app-roles-least-privilege).

## Caveats

Expand Down
25 changes: 12 additions & 13 deletions docs/architecture_decoupled.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ archiver. PostgreSQL becomes a stateless compute front-end. Lakekeeper and the
underlying object store own the storage. Decoupled mode shares the same
codebase, docker stack and extension as tiered mode. The shared mechanics -
pg_duckdb Iceberg I/O, the rewrite hook, the bakery protocol, the registry -
are in [architecture.md](architecture.md); tiered mode is in
are in [architecture.md](architecture_guides/index.md); tiered mode is in
[architecture_tiered.md](architecture_tiered.md). This document covers what is
specific to decoupled mode.

Expand Down Expand Up @@ -162,7 +162,7 @@ which would lose precision or identity:
- custom enums, `xml`, `tsvector`/`tsquery`, range types, and multirange types.
- composite types.
- arrays of `timestamptz`, `jsonb`, `json`, `interval` or a vector type, and
arrays of arrays; [Arrays](usage.md#arrays) gives the reasons.
arrays of arrays; [Arrays](supported_types.md#arrays) gives the reasons.
- pgvector's `sparsevec`.
- any type not enumerated above.

Expand Down Expand Up @@ -201,8 +201,8 @@ DELETE FROM events WHERE id = 1;
The fourth argument, `p_partition_cols`, is the table's Iceberg partitioning as
a `text[]` of `PARTITIONED BY` terms, passed to DuckDB as written; the terms,
and how a term with a comma or a quoted name is written in the array literal,
are in the [Mode 2](usage.md#mode-2-decoupled-iceberg-only) section of the
Using ColdFront guide. DuckDB refuses an unknown transform, a bad argument or a
are in the [Using ColdFront in Decoupled Mode](usage_decoupled.md) guide.
DuckDB refuses an unknown transform, a bad argument or a
column outside the schema at `CREATE TABLE`. The one check DuckDB leaves to the
first `INSERT`, a time transform on a column that is not a timestamp or date
(for `hour`, not a timestamp), `coldfront._partition_clause()` makes at the
Expand Down Expand Up @@ -517,7 +517,7 @@ Three properties are worth knowing:

## ACID Model

(This section summarizes material from [architecture.md](architecture.md)
(This section summarizes material from [architecture.md](architecture_guides/index.md)
§Concurrency and §Known Limitations applied to the decoupled scenario.)

The following table shows the status of each ACID property in decoupled mode:
Expand Down Expand Up @@ -713,8 +713,8 @@ pointing at the same Lakekeeper endpoint and S3 bucket:
- For DDL, Spock's `ddl_sql` repset replicates `CREATE/ALTER/DROP` of the
wrapper view, and the `default` repset replicates the
`coldfront.tiered_views` registry row (see
[Distributed Setup](usage.md#distributed-setup-3-node-mesh-decoupled-mode)),
so one node provisions the table and replication enables every peer's hook.
[Distributed Setup](distributed_setup.md)), so one node provisions the
table and replication enables every peer's hook.
A column `ALTER TABLE` reaches the peers the same way: the node that runs it
changes the shared Iceberg table, and its rebuilt view and registry row
replicate.
Expand Down Expand Up @@ -781,8 +781,7 @@ The call is idempotent. It puts every ColdFront table that replicates by value
in the node's replication sets: the two bakery tables, the registry and the
watermark, the storage secret, the lifecycle config and the vector routing
state (the list and the reason for each table are in the
[Distributed Setup](usage.md#what-coldfrontensure_replicated-does) section of
the Using ColdFront guide).
[Distributed Setup](distributed_setup.md#what-coldfrontensure_replicated-does) guide).
If it has not run on a peer, that peer's ack `INSERT`s are local-only and never
replicate back to the originating writer: every claim on the originator waits
at the ack barrier for an ack that never arrives.
Expand Down Expand Up @@ -836,16 +835,16 @@ Decoupled mode has the following limitations:
- A transaction block that writes a decoupled table cannot also write a
PostgreSQL table unless `duckdb.unsafe_allow_mixed_transactions` is on:
pg_duckdb refuses the PostgreSQL write, or the `COMMIT` when that write came
first. The [Caveats](usage.md#caveats) describe the rule and the risk of
setting the parameter.
first. The [Caveats](caveats.md) describe the rule and the risk of setting
the parameter.

## Next Steps

To go further with ColdFront, consult the following documents:

- The [Architecture](architecture.md) overview describes the mechanics both
- The [Architecture](architecture_guides/index.md) overview describes the mechanics both
modes share.
- The [Formal Verification](formal/README.md) document describes the TLA+ model
of the bakery protocol and how to check it.
- The [Using ColdFront](usage.md) guide covers creating decoupled tables and
- The [Using ColdFront](using_coldfront/index.md) guide covers creating decoupled tables and
setting up a distributed mesh.
Loading
Loading