Skip to content

Python definitions registry: token expansion, the prompt index, and grain - #261

Merged
jat255 merged 4 commits into
jat255/r-260-definition-token-scope-and-gistfrom
jat255/m2-definitions-registry
Sep 4, 2026
Merged

Python definitions registry: token expansion, the prompt index, and grain#261
jat255 merged 4 commits into
jat255/r-260-definition-token-scope-and-gistfrom
jat255/m2-definitions-registry

Conversation

@jat255

@jat255 jat255 commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fifth PR of M2. Adds the data-dict definitions registry, which commons owns until data-dict provides one. Closes the registry issue plus the two items that moved to it from the dictionary reader.

What it does

  • Expands {{name}} and {{table::name}} tokens in run_sql queries.
  • Builds the kind index shown in the system prompt.
  • Carries the grain metadata that call_metrics' mixed-grain guard needs.
  • Checks at construction time that each definition's table is one its source exposes.
  • Renders a table's definitions in the dictionary's first-touch entry and retrieval chunks, which the reader left as a marked seam.

Everything consumes ExportRecord; nothing reaches into an expression parser or a typed IR. When a shared data-dict interface arrives, swapping it in is a deletion rather than a rewrite. That is why the registry exists, and why it is tested before the compiler is.

First Python code to assert the shared contract

Tests run the registry over tests/shared/definitions.json as well as hand-built records. They check that every definition data-dict produced expands to its own compiled SQL, that every kind is one the index groups, and that the grain flags reach the records. #255 landed that fixture with only R asserting it; this is the Python half.

The R bugs this found, and where they went

Building this on the Python side turned up three defects in pkg-r/R/definitions.R: token scope widening through already-expanded SQL, an index cap that excluded the joining newlines, and a typeless definition losing its (kind) prefix. They are fixed in #265, which this PR now stacks on. That is also where tests/shared/definition-rendering.json lives.

This PR adds the Python runner for that fixture. Both suites now run the same 13 cases, which is what tests/shared/README.md asks for. Every case passed against this registry before the runner was written, so nothing here changed to satisfy it.

Verification

339 tests, ruff and pyrefly clean. The shared runner was checked by perturbing one expansion, one gist and one overflow flag in the fixture and confirming the three matching cases fail.

@jat255 jat255 added the py Affects the Python implementation label Sep 3, 2026
@jat255 jat255 added this to the py-M2: data layer milestone Sep 3, 2026
Base automatically changed from jat255/m2-shared-definitions to main September 3, 2026 16:06
@jat255
jat255 force-pushed the jat255/m2-definitions-registry branch from ea16360 to 8b3ea63 Compare September 3, 2026 18:16
@jat255
jat255 force-pushed the jat255/m2-definitions-registry branch from 8b3ea63 to 106bfdc Compare September 3, 2026 19:30
@jat255
jat255 changed the base branch from main to jat255/r-260-definition-token-scope-and-gist September 3, 2026 19:31
@github-actions

github-actions Bot commented Sep 3, 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/367741

Deployed from commit 501a729.

@github-actions

github-actions Bot commented Sep 3, 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/2547

Deployed from commit 501a729.

The registry surface commons owns whatever data-dict eventually provides:
{{name}} and {{table::name}} expansion, the kind index for the prompt,
grain metadata for call_metrics' mixed-grain guard, and the check that a
definition's table is one the source exposes.

Everything consumes ExportRecord and nothing reaches into an expression
parser or a typed IR. That rule is what makes replacing this with a shared
data-dict interface a deletion rather than a rewrite, and it is why the
registry can be built and tested before the compiler exists.

The dictionary's first-touch entry and its retrieval chunks now render a
table's definitions, which the reader left as a marked seam. Both show
compiled SQL rather than the authored expression, since the expression is
in data-dict's language and the model writes SQL.

Tests run the registry against tests/shared/definitions.json as well as
against hand-built records: every definition data-dict produced expands to
its own compiled SQL, and each kind is one the index groups. This is the
first Python code to consume that contract.
…e gist

Four defects, each reproduced first.

Token resolution ran against SQL that earlier expansions had already
rewritten, so a definition whose compiled SQL named another table brought
that table into scope for a later bare token. Every token now resolves
against the query as written, and substitution happens afterwards.

Retrieval chunks carried only the kind and type, so a retrieved definition
named a token without saying what it expands to. They carry the same gist
as the first-touch entry now, which is compiled SQL and notes, never the
authored expression.

An absent type reached the prompt as the word "None". data-dict omits the
type when no single one is inferred, so it is left out rather than printed.
pkg-r loses the entire gist in this case, filed as #259.

The index cap counted line lengths but not the newlines joining them, so
the result could exceed the cap. It measures the joined text.
The fixture landed in #265 with only the R suite executing it, and
tests/shared/README.md asks for both runners to land with a fixture. The
registry exists here, so Python runs the same 13 cases from the same file:
which queries expand and to what, the gist, and the index under a cap.

Replaces the integrity-only test that stood in for this. Refusals assert
the reason the fixture names, through a map to this package's message
wording, which is what the R runner does with its own.

Every case passes without touching the registry. Checked by perturbing one
expansion, one gist and one overflow flag in the fixture and confirming the
three matching cases fail.
Self-review found the gist collapsing every whitespace run while the
shared contract keeps authored whitespace; the fixture now pins the
rule with a double-space case. Also from that pass:

- pin the qualified-token refusals (table absent, unknown name) in
  tests/shared/definition-rendering.json, synced copy included
- restore the fixture-integrity guards dropped with
  test_definition_rendering_fixture.py: both sides of the index cap
  and a typeless gist case
- cover the qualified and legacy-dotted refusal paths and multi-source
  build_registry/for_source
- build_registry: tolerate tables = None instead of crashing past the
  getattr default
- correct stale docstrings: the compiler is not present yet, and the
  registry now runs the definitions.json records
@jat255
jat255 force-pushed the jat255/m2-definitions-registry branch from 1840df1 to 501a729 Compare September 4, 2026 03:44
@jat255
jat255 merged commit 82ac0fe into main Sep 4, 2026
13 checks passed
jat255 added a commit that referenced this pull request Sep 4, 2026
…ll three as a shared fixture (#265)

* fix(r): resolve definition tokens against the query as written

Three defects in pkg-r/R/definitions.R, each found while building the
Python registry and each pinned here as a shared fixture rather than as an
R-only test.

expand_definitions() resolved each token against SQL that earlier
expansions had already rewritten, so a definition whose compiled SQL named
another table brought that table into scope for the tokens that followed.
That defeats the check keeping a bare token bound to its own table. Every
token now resolves against the query as written, and substitution happens
afterwards. Closes #260.

definition_index_text() capped on cumsum(nchar(index)) but joined the kept
lines with newlines, so the rendered index could exceed cap_chars by one
character per line beyond the first, and definitions_overflow() measured
the same way and could report no overflow. Both measure the joined text.

definition_gist() built its head with sprintf("(%s, %s)", kind, type),
which returns character(0) for a definition data-dict inferred no type
for, so c() dropped the element and the gist rendered without its "(kind)"
prefix. The type is omitted and the kind kept. Note this is narrower than
#259 claims: the description and the compiled SQL did survive, so the
model was not left with a bare token. Closes #259.

tests/shared/definition-rendering.json pins all three as behaviour both
packages must agree on: which queries expand and to what, the gist text,
and the index under a cap. Refusals pin the fact of refusal and a reason
slug rather than the message, which is idiomatic to each language. The two
index cases sit on the exact boundary, so they fail against the old cumsum
rule rather than passing by accident. The R suite runs the cases; the
Python suite checks the fixture's integrity until #261 lands its registry,
at which point it runs them too. All 13 cases already pass against that
registry unchanged.

* refactor(r): make definition_gist() type check NULL-only

Both call sites pass dictionary lists, where an absent type is NULL and
length(def$type) == 0 already catches it. The is.na() arm was only
reachable from registry rows, which never reach definition_gist(), so
drop it rather than answer the same question two ways.

* Simplify comments to be more concise and reference issue numbers

* Simplify comment in test helper definitions
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Cleaned up 3 preview bundle(s) on https://dogfood.team.pct.posit.it: 367500, 367722, 367741

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Cleaned up 3 preview bundle(s) on https://connect.staging.pct.posit.it: 2521, 2546, 2547

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

py Affects the Python implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant