Skip to content

docs: propose native DuckLake layered storage (SQLite-catalog) - #74

Open
db-tycoon-stephen wants to merge 5 commits into
v0.1.12from
docs/ducklake-proposal
Open

docs: propose native DuckLake layered storage (SQLite-catalog)#74
db-tycoon-stephen wants to merge 5 commits into
v0.1.12from
docs/ducklake-proposal

Conversation

@db-tycoon-stephen

@db-tycoon-stephen db-tycoon-stephen commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What

Adds docs/proposals/ducklake-layered-storage.md — a storage-engine proposal for giving each warehouse layer its own DuckLake catalog (SQLite metadata + Parquet, S3-able), composed via ATTACH; dbt reads raw read-only and materializes into mart.

Docs-only, one new file.

Why

Came out of a 4-spike investigation (all green; DuckDB 1.5.3, ducklake e6a3bd0a, real Rill 0.86, dbt-duckdb 1.10.1). Headline finding corrects shipped docs (docs/commands/data/analyze.md:68): the read-while-ingest lock that justified the Parquet bridge for Rill is a property of the catalog metadata backend (DuckDB-file locks per-process), not of DuckLake or SQLite. A SQLite-backed catalog supports live Rill reads during ingest — confirmed with the real Rill binary, 0 lock conflicts.

Validated

  • Quack and DuckLake do not compose (fronting DuckLake with Quack ruled out).
  • DuckDB-file catalog backend locks; SQLite is multi-process safe.
  • Real Rill 0.86 reads a ducklake:sqlite: catalog live during ingest, 0 conflicts.
  • dbt-duckdb materializes raw-catalog → mart-catalog via profiles.yml attach:.

Where this lands now

Drafted 2026-06-21, when v0.1.10 was still the security pass and DuckLake had no owner in the plan. Both have moved:

So this is no longer a standalone track competing for a slot. It's the design evidence feeding M6: the corrected lock model, the validated dbt profile shape, and the four spike results are what M6 would otherwise have to rediscover. The "Proposed phasing" section predates the milestone and its sequencing is M6's to set — the doc now says so.

Merging also fixes three dangling references. PTC-41, PTC-42, and PTC-43 all point readers at docs/proposals/ducklake-layered-storage.md for the design and evidence, and that file exists only on this branch.

Freshness re-check (2026-08-02)

Rebased onto v0.1.12, the active release branch (CONTRIBUTING.md: feature and fix PRs target the release branch, not main). This PR previously targeted main; the rebase used --onto so the four PTC-96 commits that are on main but not on v0.1.12 don't ride along. Every code reference in "How it maps to the current code" was verified against both branches — none had rotted:

Reference Status on main and v0.1.12
ingestion/ducklake_config.py misnamed Still true — untouched since v0.1.0, still a dlt filesystem/Parquet destination
DatabaseConfig has two fixed fields Still true — moved (:215 on main, :212 on v0.1.12), so the doc now cites the bare path
observability_dbt.attach_metadata_to_profiles Still there, unchanged
analyze.md:68 carries the wrong lock rationale Still uncorrected (#71 open)

mkdocs build --strict and ruff==0.15.20 (the version v0.1.12 pins in its dev group) both pass locally. The new page isn't in mkdocs.yml's not_in_nav list, which is fine — ingestion-architecture.md and proposals/v0.1.10-scope.md aren't either, and unlisted pages are INFO-level, not a strict failure.

Relationship

Open risk

data_path: s3://… is unproven (all spikes used local paths) — gated as Phase 1, and now a question for M6 rather than for this doc.

Review status

Three rounds from Gemini Code Assist, all five threads resolved (dbt attach field validation, undefined link, READ_ONLY TRUE, raw data_path, missing schema). No further bot review will arrive — Gemini was opted out repo-wide after this PR opened (#173).

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a proposal for native DuckLake layered storage using a SQLite-catalog to enable a local-first lakehouse on object storage. The review feedback highlights a validation issue with the proposed dbt-duckdb profile configuration, which does not support custom fields like is_ducklake or options out-of-the-box, and identifies a missing markdown reference link for [no-legacy stance].

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread docs/proposals/ducklake-layered-storage.md
Comment thread docs/proposals/ducklake-layered-storage.md Outdated
db-tycoon-stephen added a commit that referenced this pull request Jun 22, 2026
…d link

- Clarify the attach syntax (is_ducklake/options) is native in dbt-duckdb
  >= 1.10 (validated on 1.10.1 in spike 4); older versions reject it and
  need a custom plugin. Implementation must pin a version floor.
- Replace the undefined [no-legacy stance] markdown reference with plain text.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@db-tycoon-stephen

Copy link
Copy Markdown
Contributor Author

Review triage — commit ae56ca6

Addressed the Gemini Code Assist review:

  • Undefined [no-legacy stance] markdown link → replaced with plain text.
  • ↩️ "dbt-duckdb attach rejects is_ducklake/options" → accurate for older dbt-duckdb, but not for 1.10.1 (the version this proposal targets): the Attachment model declares options/is_ducklake as first-class fields, and spike 4 ran a real dbt run with this exact profile (materialized into the mart DuckLake catalog, 3 snapshots). Rather than dismiss it, added an explicit dbt-duckdb ≥ 1.10 version-floor note with the plugin fallback for older versions.

For reviewers: this PR is docs-only (a proposal) and not part of v0.1.10 (the security pass). Tracked as #73 / PTC-41. Open risk noted in the doc: data_path: s3://… is unproven (Phase 1).

@db-tycoon-stephen

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a proposal for a native DuckLake layered storage architecture using a SQLite-backed catalog to enable multi-process, local-first lakehouses. The feedback identifies two key improvements in the proposal's examples: ensuring the SQL ATTACH statement uses READ_ONLY TRUE for better DuckDB version compatibility, and adding the missing data_path option to the raw attachment in the dbt profile configuration.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread docs/proposals/ducklake-layered-storage.md
Comment thread docs/proposals/ducklake-layered-storage.md
db-tycoon-stephen added a commit that referenced this pull request Jun 23, 2026
A DuckLake catalog stores data_path in metadata at creation, so re-attaching
an existing catalog (raw, created by ingestion) needs no data_path — only the
catalog created here (mart) specifies it. Verified by re-attaching a
ducklake:sqlite: catalog read-only with no data_path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@db-tycoon-stephen

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request adds a new proposal document (docs/proposals/ducklake-layered-storage.md) outlining a native DuckLake layered storage architecture using a SQLite-catalog. The feedback points out that the dbt profile YAML example in the proposal is missing the required schema field, which would cause dbt validation to fail, and suggests adding a default schema to make the example valid.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread docs/proposals/ducklake-layered-storage.md
db-tycoon-stephen added a commit that referenced this pull request Jun 23, 2026
…view)

The condensed profile example omitted schema:, which dbt requires (spike 4's
working profile had it). Add schema: main to keep the example copy-pasteable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
db-tycoon-stephen added a commit that referenced this pull request Aug 2, 2026
…d link

- Clarify the attach syntax (is_ducklake/options) is native in dbt-duckdb
  >= 1.10 (validated on 1.10.1 in spike 4); older versions reject it and
  need a custom plugin. Implementation must pin a version floor.
- Replace the undefined [no-legacy stance] markdown reference with plain text.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
db-tycoon-stephen added a commit that referenced this pull request Aug 2, 2026
A DuckLake catalog stores data_path in metadata at creation, so re-attaching
an existing catalog (raw, created by ingestion) needs no data_path — only the
catalog created here (mart) specifies it. Verified by re-attaching a
ducklake:sqlite: catalog read-only with no data_path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
db-tycoon-stephen added a commit that referenced this pull request Aug 2, 2026
…view)

The condensed profile example omitted schema:, which dbt requires (spike 4's
working profile had it). Add schema: main to keep the example copy-pasteable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
db-tycoon-stephen added a commit that referenced this pull request Aug 2, 2026
Rebased onto main after six weeks. Three freshness fixes, no change to
the design or the spike findings:

- v0.1.10 shipped 2026-07-21, so stop describing it in the future tense.
- Note that the ingestion rewrite's M6 (#87) now owns the DuckLake
  surface. The phasing here predates that milestone; M6 sets sequencing.
- Drop the `project.py:141` line number (DatabaseConfig has since moved
  to :215) — the bare path can't rot again.

Every code reference in "How it maps to the current code" was re-checked
against main: ducklake_config.py is untouched since v0.1.0, DatabaseConfig
still has the two fixed fields, attach_metadata_to_profiles still lives in
scaffolding/observability_dbt.py, and analyze.md:68 still carries the
error this proposal corrects.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
db-tycoon-stephen and others added 5 commits August 2, 2026 17:12
Storage-engine proposal from a 4-spike investigation (all green): one
DuckLake catalog per layer (SQLite metadata + Parquet, S3-able), composed
via ATTACH; dbt reads raw read-only and materializes into mart.

Key finding corrects docs/commands/data/analyze.md:68 — the
read-while-ingest lock is a property of the catalog metadata backend
(DuckDB-file locks per-process), not of DuckLake or SQLite. Real Rill 0.86
reads a ducklake:sqlite: catalog live during ingest with zero conflicts.

Builds on the shipped layer-aware data model (#30), unblocks layer-granular
backup (#31). Not part of v0.1.10. Filed #71, #72, #73.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d link

- Clarify the attach syntax (is_ducklake/options) is native in dbt-duckdb
  >= 1.10 (validated on 1.10.1 in spike 4); older versions reject it and
  need a custom plugin. Implementation must pin a version floor.
- Replace the undefined [no-legacy stance] markdown reference with plain text.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A DuckLake catalog stores data_path in metadata at creation, so re-attaching
an existing catalog (raw, created by ingestion) needs no data_path — only the
catalog created here (mart) specifies it. Verified by re-attaching a
ducklake:sqlite: catalog read-only with no data_path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…view)

The condensed profile example omitted schema:, which dbt requires (spike 4's
working profile had it). Add schema: main to keep the example copy-pasteable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebased onto v0.1.12 after six weeks. Three freshness fixes, no change
to the design or the spike findings:

- v0.1.10 shipped 2026-07-21, so stop describing it in the future tense.
- Note that the ingestion rewrite's M6 (#87) now owns the DuckLake
  surface. The phasing here predates that milestone; M6 sets sequencing.
- Drop the `project.py:141` line number — DatabaseConfig has since moved
  (:215 on main, :212 on v0.1.12), so the bare path can't rot again.

Every code reference in "How it maps to the current code" was re-checked
against both branches: ducklake_config.py is untouched since v0.1.0,
DatabaseConfig still has the two fixed fields, attach_metadata_to_profiles
still lives in scaffolding/observability_dbt.py, and analyze.md:68 still
carries the error this proposal corrects.

Co-Authored-By: Claude Opus 5 (1M context) <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.

1 participant