[default values] Tables: add a server-stamped per-table config map to GetTableResponseBody and capture it client-side#644
Merged
Conversation
Add a server-stamped, READ_ONLY runtimePolicy field (RuntimePolicy + PolicyDirective response components) as a forward-compatible channel for delivering per-table client directives at runtime, without re-rolling the Java client fleet. The read-bridge gate is its first intended consumer. The field is null by default, so there is no behavior change: the server PolicyEngine stamp and the client-side reader are follow-ups. Typed envelope + opaque per-feature payload means new features are new map entries rather than API/schema changes; READ_ONLY keeps it off the write path and out of persisted metadata.
doRefresh now keeps the full GetTableResponseBody (instead of mapping it straight to the table location) and stashes the server-stamped runtimePolicy in an AtomicReference, exposed to subclasses via the new protected currentRuntimePolicy(). Absent policy => null, the safe default. This makes the per-table runtime policy available at the loadMetadata seam so subclasses can gate read-time behavior (e.g. the li-openhouse column-default overlay) without a client re-roll. Behaviorless on its own: the base client has no overlay to gate, and the policy is read-only, never sent back on writes.
The "runtime policy" / "directive" naming was domain-specific and collided with the existing table-governance Policies object (it forced a Javadoc disclaimer). Rename the channel to plain-language feature-flag terms that state what it does: the server controls per-table client behavior at runtime. RuntimePolicy -> FeatureFlags (envelope) PolicyDirective -> FeatureFlag (per-feature entry) .directives map -> .flags .policyVersion -> .version GetTableResponseBody.runtimePolicy -> featureFlags OpenHouseTableOperations.currentRuntimePolicy() -> currentFeatureFlags() Behavior, READ_ONLY/side-channel semantics, and the typed-envelope + opaque-payload contract are unchanged; this is a pure rename. The generated client model regenerates as FeatureFlags/FeatureFlag. Cheapest moment to rename: the field is still null end-to-end and no consumer has pinned to the generated type yet. Co-authored-by: Cursor <cursoragent@cursor.com>
Add OpenHouseTableOperationsTest coverage for the runtime feature-flag
channel:
- currentFeatureFlags() is null before any refresh (safe default)
- doRefresh captures the server-stamped featureFlags
- absent featureFlags on the response => null
- a later refresh that stops stamping clears the stale value (the held
policy is the latest snapshot, never sticky)
- the typed envelope + opaque payload deserializes from a response, and
unknown envelope/flag fields are tolerated (FAIL_ON_UNKNOWN_PROPERTIES)
Co-authored-by: Cursor <cursoragent@cursor.com>
This was referenced Jun 28, 2026
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jun 29, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource (+ NoColumnDefaults no-op default): the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). - TableConfigResolver + ReadBridgeConfigResolver: OSS-owned resolver that owns the config key (openhouse.read-bridge) and payload contract, returning the per-table config map the handler stamps via withConfig. - OpenHouseTableOperations.loadMetadata: the client gate reads the read-bridge config key and overlays per-column initial-defaults; the overlay transform (applyColumnDefaults) is a marked TODO so the gate runs end-to-end while behavior is unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jun 29, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource (+ NoColumnDefaults no-op): the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). - TableConfigResolver + ReadBridgeConfigResolver: the server-side encoder that owns the config key (openhouse.read-bridge) and the payload contract. - ReadBridgeConfig (client decoder; mirror of the resolver) + ReadBridgeOverlay (the overlay transform, a marked TODO) keep OpenHouseTableOperations slim — its loadMetadata just decodes the config and applies the overlay. ReadBridgeConfig is unit-tested in isolation (ReadBridgeConfigTest). Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jun 29, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource (+ NoColumnDefaults no-op): the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). - TableConfigResolver + ReadBridgeConfigResolver: the server-side encoder that owns the config key (openhouse.read-bridge) and the payload contract. - ReadBridgeConfig (client decoder; mirror of the resolver, unit-tested in isolation) + ReadBridge (the read-time bridge entry point that applies the decoded behavior; the column-default overlay is a marked TODO and the place further V3 features get backported) keep OpenHouseTableOperations slim — its loadMetadata just calls ReadBridge.apply(raw, currentConfig()). Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jun 29, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource: the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). Open-source default is a no-op lambda in ApiConfig; a deployment overrides this bean (e.g. li-openhouse, from avro.schema.literal). - ReadBridgeConfigResolver: the server-side encoder that owns the config key (openhouse.read-bridge) and payload contract, wired into the handler. - ReadBridge (client): decodes that config and applies the overlay at metadata-load time (the column-default transform is a marked TODO, and the place further V3 features get backported). Mirror of the server encoder, unit-tested in isolation. Keeps OpenHouseTableOperations.loadMetadata to one delegating call. Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jun 29, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource: the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). Open-source default is a no-op lambda in ApiConfig; a deployment overrides this bean (e.g. li-openhouse, from avro.schema.literal). - ReadBridgePayload: the typed payload of the read-bridge config entry. The server (ReadBridgeConfigResolver) and client (ReadBridge) ser/deser it with Jackson, so neither hand-crafts JSON; field names are declared once via @JsonProperty. Mirrored across the module split. - ReadBridgeConfigResolver: server-side encoder that owns the config key (openhouse.read-bridge), wired into the handler. - ReadBridge (client): decodes the payload and applies the overlay at metadata-load time (the column-default transform is a marked TODO, and the place further V3 features get backported). Keeps loadMetadata to one call. Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
…ntion) Conform the channel wire to Iceberg REST LoadTableResponse.config: replace the bespoke featureFlags envelope on GetTableResponseBody with a config Map<String,String>, and capture it client-side as currentConfig(). - Drop the typed FeatureFlags/FeatureFlag models; the wire is a string map (READ_ONLY, nullable). Unknown keys are ignored by clients. - OpenHouseTableOperations captures `config` (currentConfig()) instead of a typed envelope. - TablesMapper ignores `config` (stamped separately by the API handler). Behaviorless on its own; the server stamp + client consumer land in the read-bridge PR stacked on this one. Co-authored-by: Cursor <cursoragent@cursor.com>
7c276f0 to
fdfaf48
Compare
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jun 29, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource: the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). Open-source default is a no-op lambda in ApiConfig; a deployment overrides this bean (e.g. li-openhouse, from avro.schema.literal). - ReadBridgePayload: the typed payload of the read-bridge config entry; server (ReadBridgeConfigResolver) and client (ReadBridge) ser/deser it with Jackson, so neither hand-crafts JSON. Mirrored across the module split. - ReadBridgeConfigResolver: server-side encoder that owns the config key (openhouse.read-bridge), wired into the handler. - ReadBridge (client): decodes the payload and applies the overlay at metadata-load time (the column-default transform is a marked TODO, and the place further V3 features get backported). Keeps loadMetadata to one call. Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jun 29, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource: the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). Open-source default is a no-op lambda in ApiConfig; a deployment overrides this bean (e.g. li-openhouse, from avro.schema.literal). - ReadBridgePayload: the typed payload of the read-bridge config entry; server (ReadBridgeConfigResolver) and client (ReadBridge) ser/deser it with Jackson, so neither hand-crafts JSON. Mirrored across the module split. - ReadBridgeConfigResolver: server-side encoder that owns the config key (openhouse.read-bridge), wired into the handler. - ReadBridge (client): decodes the payload and applies the overlay at metadata-load time (the column-default transform is a marked TODO, and the place further V3 features get backported). Keeps loadMetadata to one call. Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jun 29, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource: the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). Open-source default is a no-op lambda in ApiConfig; a deployment overrides this bean (e.g. li-openhouse, from avro.schema.literal). - ReadBridgeConfigResolver: server-side encoder that stamps each default as a flat namespaced config entry (openhouse.read-bridge.column-default.<fieldId> = single-value JSON) — no envelope/POJO; the config map carries the structure. - ReadBridge (client): decodes those entries and applies the overlay at metadata-load time (the column-default transform is a marked TODO, and the place further V3 features get backported). Keeps loadMetadata to one call. Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jun 30, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource: the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). Open-source default is a no-op lambda in ApiConfig; a deployment overrides this bean (e.g. li-openhouse, from avro.schema.literal). - ReadBridgeConfigResolver: server-side encoder that stamps each default as a flat namespaced config entry (openhouse.read-bridge.column-default.<fieldId> = single-value JSON) — no envelope/POJO; the config map carries the structure. - ReadBridge (client): decodes those entries and applies the overlay at metadata-load time (the column-default transform is a marked TODO, and the place further V3 features get backported). Keeps loadMetadata to one call. Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jul 1, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource: the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). Open-source default is a no-op lambda in ApiConfig; a deployment overrides this bean (e.g. li-openhouse, from avro.schema.literal). - ReadBridgeConfigResolver: server-side encoder that stamps each default as a flat namespaced config entry (openhouse.read-bridge.column-default.<fieldId> = single-value JSON) — no envelope/POJO; the config map carries the structure. - ReadBridge (client): decodes those entries and applies the overlay at metadata-load time (the column-default transform is a marked TODO, and the place further V3 features get backported). Keeps loadMetadata to one call. Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
shanthoosh
approved these changes
Jul 3, 2026
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jul 4, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource: the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). Open-source default is a no-op lambda in ApiConfig; a deployment overrides this bean (e.g. li-openhouse, from avro.schema.literal). - ReadBridgeConfigResolver: server-side encoder that stamps each default as a flat namespaced config entry (openhouse.read-bridge.column-default.<fieldId> = single-value JSON) — no envelope/POJO; the config map carries the structure. - ReadBridge (client): decodes those entries and applies the overlay at metadata-load time (the column-default transform is a marked TODO, and the place further V3 features get backported). Keeps loadMetadata to one call. Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
cbb330
added a commit
to cbb330/openhouse
that referenced
this pull request
Jul 4, 2026
Adds the open-source read-bridge feature on top of the per-table `config` channel (linkedin#644): - ColumnDefaultsSource: the single open-source/closed-source seam (field-id -> Iceberg single-value JSON). Open-source default is a no-op lambda in ApiConfig; a deployment overrides this bean (e.g. li-openhouse, from avro.schema.literal). - ReadBridgeConfigResolver: server-side encoder that stamps each default as a flat namespaced config entry (openhouse.read-bridge.column-default.<fieldId> = single-value JSON) — no envelope/POJO; the config map carries the structure. - ReadBridge (client): decodes those entries and applies the overlay at metadata-load time (the column-default transform is a marked TODO, and the place further V3 features get backported). Keeps loadMetadata to one call. Behaviorless until a ColumnDefaultsSource is supplied; fail-closed throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a generic, server-stamped, per-table client
configmap toGetTableResponseBodyand captures it inOpenHouseTableOperationsso subclasses can read it. It follows the Iceberg RESTLoadTableResponse.configconvention — aMap<String,String>of client-side behavior overrides the server controls at runtime, without re-rolling the slow-to-upgrade Java client fleet. No behavior change: the map is null/empty until a server stamps it, and the base client has nothing to act on.Changes
Client-facing API Changes
configfield (Map<String,String>) onGetTableResponseBody, modeled on the Iceberg REST load-tableconfig. Namespaced keys (e.g.openhouse.read-bridge); clients ignore keys they do not understand.doRefreshalready fetches a liveGetTableResponseBodyon every table load (and on commit responses) but discarded all butgetTableLocation()— it is the natural, already-present, server-controlled, zero-staleness delivery channel. The generated client setsFAIL_ON_UNKNOWN_PROPERTIES = false, so a new response field cannot break older clients (and unknown config keys are simply carried). Same additive, nullable, READ_ONLY pattern assortOrderetc.Internal API Changes
OpenHouseTableOperations.doRefreshkeeps the full response and stashesconfigin anAtomicReference, exposed to subclasses via the newprotected currentConfig(). READ_ONLY + side-channel: never sent back on writes.TablesMapper(the table DTO serializer into gettableresponsebody) ignoresconfig(@Mapping(target = "config", ignore = true)) — it is stamped separately, not sourced fromTableDto.New Features
configentries rather than an API/schema change or client regen.Testing Done
Compile/codegen verified (
:services:tables,:client:tableclient,:integrations:java:iceberg-1.2:openhouse-java-runtime); the client regenerates withgetConfig()returningMap<String,String>.OpenHouseTableOperationsTestcovers:currentConfig()null before refresh;doRefreshcaptures/clearsconfig; the REST-style string map deserializes from a response and tolerates unknown fields.Stack
#644 (channel) → #645 (read-bridge mechanism) → li-openhouse #2166 (li column-default source from avro.schema.literal)
This is the substrate PR — intentionally behaviorless on its own.
Next steps (this PR)
This PR delivers only the channel; it stays inert until two further pieces exist, both required, and both delivered by the next PR in the stack:
config(it is null until something stamps it) — required, delivered by [default values] Tables: apply server-supplied per-column defaults at read time #645 viaReadBridgeConfigResolver+ theColumnDefaultsSourceseam.currentConfig()and acts on it — required, delivered by [default values] Tables: apply server-supplied per-column defaults at read time #645's read-bridge metadata overlay, driven by the column defaults that #2166 supplies.