Skip to content

Iceberg REST Phase 1 [1/3]: Read-only contract and codegen - #689

Open
cbb330 wants to merge 8 commits into
mainfrom
chbush/iceberg-rest-1-codegen
Open

Iceberg REST Phase 1 [1/3]: Read-only contract and codegen#689
cbb330 wants to merge 8 commits into
mainfrom
chbush/iceberg-rest-1-codegen

Conversation

@cbb330

@cbb330 cbb330 commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Part 1 of 3 for a read-only Iceberg REST Catalog facade.

Checks in the full Apache Iceberg 1.11.0 REST OpenAPI. OpenHouse support is opt-in via x-openhouse-support: supported on operations (missing = unsupported). The build codegens only supported operations; marking support or changing a supported signature fails compilation until the facade implements it. No YAML checksum pin.

Changes

  • Client-facing API Changes
  • Internal API Changes
  • Bug Fixes
  • New Features
  • Performance Improvements
  • Code Style
  • Refactoring
  • Documentation
  • Tests

Internal API Changes

  • Vendors full Iceberg 1.11 REST OpenAPI with opt-in x-openhouse-support: supported markers.
  • Build derives codegen input + IcebergRestOpenHouseSupport.SUPPORTED_ENDPOINTS from supported ops only.
  • Codegen produces Spring interfaces for config / listTables / loadTable / tableExists.

Upgrade model

Merge newer upstream YAML → add x-openhouse-support: supported where needed → compile. Unsupported ops need no annotation, so merges stay quiet.

Testing Done

./gradlew :services:tables:icebergRestAssertSupportAnnotations :services:tables:icebergRestCodegen

Runtime tests are in #690 / #691.

Additional Information

  • Large PR broken into smaller PRs, and PR plan linked in the description.

Merge in order:

  1. Iceberg REST Phase 1 [1/3]: Read-only contract and codegen #689 — Contract and codegen ← you are here
  2. Iceberg REST Phase 1 [2/3]: Runtime facade and unit coverage #690 — Runtime facade and unit coverage
  3. Iceberg REST Phase 1 [3/3]: Client and integration validation #691 — Client and integration validation

cbb330 added 3 commits March 11, 2026 15:47
Vendor the upstream Apache Iceberg REST OpenAPI spec (v1.10) and wire
Polaris-aligned codegen into the services/tables Gradle build:

- spec/iceberg-rest-catalog-open-api.yaml: upstream spec as source of truth
- Gradle tasks: setUpOpenApiCliForIcebergRest, validateIcebergRestOpenApiSpec,
  generateIcebergRestOpenApiServer with importMappings/typeMappings to map
  spec schemas to real Iceberg library types (no model generation)
- Post-processing for Iceberg 1.10-only types mapped to Object (compatibility
  with our 1.5.2 fork)
- compileJava depends on codegen; check depends on spec validation
- jackson-databind-nullable dependency for generated code
- Strip non-upstream comments (CODE_COPIED_TO_POLARIS, version marker) so
  the vendored spec is byte-for-byte identical to apache-iceberg-1.10.0
- Add verifyIcebergRestSpecSync Gradle task that downloads the upstream spec
  from the pinned tag and fails if it differs from the vendored copy
- Wire verifyIcebergRestSpecSync into the check task so CI catches drift
Generate the supported profile deterministically and resolve the generator through Gradle so unsupported APIs cannot leak into the server surface.
cbb330 added 5 commits August 21, 2026 09:21
Drop the full upstream vendored YAML and Python profile generator from the
build surface so codegen depends on one constant Phase 1 contract file.
Add a maintainer script and Gradle task that fetch an Iceberg tag, rebuild
the Phase 1 allowlisted profile, and refresh the pinned checksum without
making the build depend on network or Python regeneration.
Check in the complete Apache Iceberg 1.11 REST contract with
x-openhouse-support markers, assert every operation is annotated, codegen
only supported ops, and drop the upgrade script.
Drop unsupported markers and the YAML checksum pin so upgrades are a
plain merge plus x-openhouse-support: supported where needed.
Keep services/tables/build.gradle lean and simplify filtering by retaining
full OpenAPI components while still codegening only supported operations.
@cbb330

cbb330 commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator Author

Gradle LOC cleanup: Iceberg REST OpenAPI build logic now lives in openhouse.iceberg-rest-openapi (buildSrc). services/tables/build.gradle is back to a one-line plugin apply + normal deps.

@mkuchenbecker mkuchenbecker left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is part of a coordinated review of the #689/#690/#691 stack (architecture, Iceberg REST spec conformance, and testing passes). It was generated based on the review skills at https://github.com/mkuchenbecker/code-review-skills — linked so the criteria being judged are inspectable: arch-review (module topology, contracts, and the error channel), testing-review (testing as falsification: tests derived from claims, suites judged by diffing the tests that should exist against those that do), plus an Iceberg REST spec conformance pass against the vendored YAML.

Verdict for this PR: the contract-first shape is right, and the vendored YAML is byte-identical to upstream apache-iceberg-1.11.0 apart from the header comment and the four x-openhouse-support annotation lines, and the SHA-256 recorded in its header matches the upstream file. Two things need attention: the mechanism's central safety claim ("marking an operation supported fails compilation until the facade implements it") is not enforced by the build, and nothing verifies the vendored spec stays faithful to upstream after future merges. One structural follow-up on the convention plugin.

3 inline comments: 1 fix-before-merge, 1 fix-before-enabling, 1 follow-up.


Generated by Claude Code

'--global-property',
'apis,models=CatalogConfig:ListTablesResponse,apiTests=false,apiDocs=false,modelTests=false,modelDocs=false,supportingFiles=',
'--additional-properties',
'interfaceOnly=true,useTags=true,skipDefaultInterface=false,hideGenerationTimestamp=true,useSpringBoot3=false,openApiNullable=false'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Fix before merge — the documented codegen guardrail does not exist. The spec header (lines 26–31) and docs/iceberg-rest-catalog.md both state that marking an operation x-openhouse-support: supported without implementing it "fails compilation". With skipDefaultInterface=false on this line, every generated operation is a Java default method returning an empty HTTP 501 — so it compiles, is added to SUPPORTED_ENDPOINTS, and is advertised as supported by GET /v1/config; clients that trust the advertisement call it and get a bodyless 501. Second hole: an operation under a new spec tag generates an interface no class implements, so no route is registered at all. Fix: set skipDefaultInterface=true so generated methods are abstract (restoring the documented compile failure), add a startup assertion that every SUPPORTED_ENDPOINTS entry has a registered Spring route (covers the new-tag hole), and align the two prose claims.

# specific language governing permissions and limitations
# under the License.
#

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Fix before enabling — the recorded upstream SHA is a comment nobody checks. The header records the SHA-256 of the upstream Iceberg 1.11.0 file, and it is correct today: stripping the header and annotation lines yields a file whose hash matches the recorded value. But no build task recomputes it, so a conflict resolution during the next spec upgrade can silently diverge the vendored contract while the header keeps asserting fidelity. Fix: a ~10-line task wired into check — strip the header comment and the x-openhouse-support lines, hash, compare against the recorded value, and fail with the upstream URL in the message. No network access needed.

* Codegens Spring interfaces for supported ops only and emits
* IcebergRestOpenHouseSupport.SUPPORTED_ENDPOINTS for GET /v1/config.
*/
def icebergRestSpec = rootProject.file('spec/iceberg-rest-catalog-open-api.yaml')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Follow-up — the shared convention plugin hardcodes its single consumer. The spec path here, plus the Java package and support-class names below, embed one project's identity in a shared buildSrc plugin, and generated sources are attached by mutating compileJava.source rather than registering a source directory. Lift these into plugin extension properties with the current values as defaults, and register the generated directories via sourceSets.main.java.srcDir(...) so the task dependency flows through builtBy.

@aastha25

Copy link
Copy Markdown
Contributor

@cbb330 , Is there a design doc articulating the points of integration for IRC, known compatibility issues & path to resolution? any internal docs and sharing internally within team channel is good.

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.

3 participants