Skip to content

Merge a warehouse catalog into an authored dictionary - #275

Merged
jat255 merged 3 commits into
jat255/xp65-catalog-corefrom
jat255/xp65-catalog-merge
Sep 6, 2026
Merged

Merge a warehouse catalog into an authored dictionary#275
jat255 merged 3 commits into
jat255/xp65-catalog-corefrom
jat255/xp65-catalog-merge

Conversation

@jat255

@jat255 jat255 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Second PR of the catalog import stack (kata task xp65). Stacked on #274. Ports catalog.R: selection into labelled relations, exclusion globs and the object cap, the manifest that decides whether a listing belongs in the prompt or behind search, catalog search, and the dictionary merge.

The python side follows the same rules used on the R side: authored prose wins, warehouse types and nullability are authoritative, identifier case normalizes per backend, and an ambiguous relative name is an error rather than a guess. Discovered columns come first in the order the warehouse reported them; authored columns with no counterpart follow.

R changes

@simonpcouch

The changes on the R side are tests only — pkg-r/R/ is untouched.

  • tests/shared/catalog-merge.json is a new cross-language contract: the three catalog limits (object cap, prompt threshold, search probe bound), exclusion-glob semantics, and seven merge scenarios with expected merged tables, columns, and definition bindings.
  • pkg-r/tests/testthat/test-catalog-merge.R is the R runner for it, covering the limits, catalog_excluded, and catalog_merge_dictionary against fixture-built relations. pkg-r/tests/testthat/fixtures/shared/catalog-merge.json is the synced copy from scripts/sync-shared-fixtures.sh.
  • One behavior the fixture newly pins on both sides: exclusion globs match the bare table name, case-sensitively.
  • The fixture's kind expectations match what catalog_merge_dictionary_table already does; adding kind to the merged table was a Python-side gap this PR closes.

@jat255
jat255 marked this pull request as draft September 4, 2026 05:49
@jat255 jat255 mentioned this pull request Sep 4, 2026
@jat255 jat255 added this to the py-M2: data layer milestone Sep 4, 2026
@jat255 jat255 added needs-manual-review Agent-created work that needs a human review py Affects the Python implementation labels Sep 4, 2026
@jat255
jat255 force-pushed the jat255/xp65-catalog-merge branch from 0fa5884 to 730db47 Compare September 5, 2026 04:58
@jat255
jat255 force-pushed the jat255/xp65-catalog-merge branch from 730db47 to 52cd57c Compare September 6, 2026 02:07
@jat255

jat255 commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

Reviewed 2026-09-05 23:24 MDT (final manual review pass).

Findings from the review were addressed in c494065:

  • Silent divergence fixed: the merge dropped Relation.kind where R carries it onto the merged table; Table gains a kind field and the merge sets it (warehouse wins, authored survives as fallback).
  • Coverage gaps closed: the search() queryable probe path and merge_dictionary's access_check are now exercised, and the object-cap and prompt-threshold boundaries are pinned at exactly-at-the-limit.
  • Shared fixture added: tests/shared/catalog-merge.json pins the three limits, exclusion-glob semantics (bare table name, case-sensitive — now documented in excluded()), and seven merge scenarios with expected tables, columns, and definition bindings. Both suites run it; the R runner passes all cases, and the three error cases were confirmed to raise the intended errors on the R side.
  • Smaller parity fixes: duplicate-label refusal now reports every duplicated label; a non-whole limit is refused cleanly; raise conditions documented on the three public functions.

Deliberately not changed: exclusion globs still match the bare table name case-sensitively (R agrees, and the fixture now pins it — a schema-qualified or case-folding exclude would be a cross-package decision, flagged for follow-up). authored_name remains settable from authored YAML; stripping it in the parse path would break round-tripping a merged dictionary through model_dump/model_validate.

Checks on the pushed head: ruff clean, pyrefly 0 errors, 761 tests pass; the new R fixture runner passes (57 expectations). Note: the full R suite could not run locally (ellmer 0.4.2 installed, pkg-r requires >= 0.5.0) — CI will be its first full run.

@jat255 jat255 removed the needs-manual-review Agent-created work that needs a human review label Sep 6, 2026
@jat255
jat255 requested a review from simonpcouch September 6, 2026 05:30
@jat255
jat255 marked this pull request as ready for review September 6, 2026 05:31
Second of the catalog import stack (kata xp65). Ports catalog.R: selection
into labelled relations, the exclusion globs and object cap, the manifest
that decides whether a listing is small enough to put in a prompt, catalog
search, and the dictionary merge.

The rules the R side settled and this keeps: authored prose wins, warehouse
types and nullability are authoritative, identifier case normalizes per
backend, and an ambiguous relative name is an error rather than a guess.
Discovered columns come first in the order the warehouse reported them, and
authored columns with no counterpart follow.

Every function here is pure over the rows a listing returns, so none of it
needs a warehouse. Running the queries that produce those rows belongs to
the per-backend readers, which is the next two PRs.

Two departures from R, both because Python's types differ. A selection entry
is a Selector rather than a TableId, because a selection may stop at a
catalog or a schema and a TableId always names a table; that also lets
id_type() be one dialect-independent function rather than an injected
backend one. And the authored table alias is a declared `authored_name`
field on Table rather than an attribute set on the fly, since the model is
pydantic.

The merge rules were confirmed to bite by letting an authored type win over
the warehouse and by leaving glob metacharacters unescaped.
…y both names

Two defects in the catalog core.

An entry naming a table whose relation the warehouse did not return was
dropped, including from the validation list, so asking for a table that is
not there became a quietly smaller selection instead of an error the backend
reports. R keeps an undiscovered stub and validates it; that is restored,
and an excluded entry is still dropped from both.

The authored_name field added in the previous commit was never read.
Relationship prose says what the author wrote, and the merge re-keys a table
to its warehouse label, so a relationship on `orders` stopped reaching the
first-touch entry of ANALYTICS.PUBLIC.ORDERS. Rendering now matches either
name.

Found by roborev job 331.
…red contract

Review follow-ups:

- The merge dropped Relation.kind where R carries it onto the merged
  table; Table gains a kind field and the merge sets it, the
  warehouse's kind winning over an authored one.
- The search() queryable probe path and merge_dictionary's access_check
  had no coverage; both are now exercised, as are the object-cap and
  prompt-threshold boundaries (exactly at the limit is allowed).
- Duplicate-label refusal now reports every duplicated label, matching
  R, and a non-whole limit is refused rather than dying in a slice.
- tests/shared/catalog-merge.json pins the cross-language contract: the
  three limits, exclusion-glob behavior over bare table names
  (case-sensitive by design), and seven merge scenarios with expected
  tables, columns, and definition bindings. Both suites run it; the R
  runner is new and passes all cases.
- Docstrings on table_registry, search, and merge_dictionary now state
  their raise conditions, and excluded() documents that matching is
  bare-name and case-sensitive.
@jat255
jat255 force-pushed the jat255/xp65-catalog-merge branch from c494065 to 73f1c1e Compare September 6, 2026 06:29
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Preview deployed to Connect (dogfood.team.pct.posit.it): https://dogfood.team.pct.posit.it/connect/#/apps/d7a36cae-8f27-448b-a478-61b81fbe3942/draft/368187

Deployed from commit 73f1c1e.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Preview deployed to Connect (connect.staging.pct.posit.it): https://connect.staging.pct.posit.it/connect/#/apps/ad662e1b-5048-4acc-9ad7-f9478c92274e/draft/2646

Deployed from commit 73f1c1e.

@jat255 jat255 added the r Affects the R implementation label Sep 6, 2026
@jat255
jat255 merged commit df4eb2f into main Sep 6, 2026
13 checks passed
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Cleaned up 1 preview bundle(s) on https://dogfood.team.pct.posit.it: 368187

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Cleaned up 1 preview bundle(s) on https://connect.staging.pct.posit.it: 2646

@jat255
jat255 deleted the jat255/xp65-catalog-merge branch September 6, 2026 23:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

py Affects the Python implementation r Affects the R implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants