Skip to content

feat(mdcode): check each deployment's tables and the metric rules of the profile it names - #564

Open
feixufeixu wants to merge 1 commit into
feat/push/tpp-3-two-phase-every-modelfrom
feat/push/tpp-4-tables-and-metric-rules
Open

feixufeixu wants to merge 1 commit into
feat/push/tpp-3-two-phase-every-modelfrom
feat/push/tpp-4-tables-and-metric-rules

Conversation

@feixufeixu

Copy link
Copy Markdown
Collaborator

A two-phase push, and kcmd profiles for a model that lists deployments, now
refuse a deployment whose tables are outside the database it deploys to. The new
deploymentTableErrors reads each entity's source from the profile the
deployment names, or from the model file for a deployment that names none.
It compares the database databaseOf gives for each source with the target's:

  1. A Spanner deployment's tables must be Spanner tables in the target database.
  2. An AlloyDB deployment's tables must be AlloyDB tables in the target
    database, which the runtime queries alone.
  3. A BigQuery deployment's tables must be BigQuery or BigLake tables, in any
    dataset of any project.

Any other source fails, so a Cloud SQL table fails every deployment. An entity
with no source is skipped, and so is a deployment whose profile is a legacy
wrapper. checkBeforeWrites runs the check on every deployment, whether or not
--deployment selects it, and under --no-deployment too. In the report each
error belongs to the deployment's profile.

A deployment that names a profile is now held to the metric rules of its
engine under that profile. validateDeployments reads the profile from
model.profiles, so it leaves out a legacy wrapper, and leaves a profile that
does not apply to the completeness check:

  1. A metric the profile leaves unavailable is held to no rule: one it names
    in metrics_exclude, and one that reads a field it excludes or leaves
    unbound.
  2. A Spanner deployment fails while its profile leaves a metric available.
  3. A BigQuery deployment holds each metric its profile leaves to the measure
    rule, with the keys the profile states.

checkBeforeWrites runs validateDeployments once for each profile the
deployments use. In the report each error belongs to that profile, and a
problem that two deployments on one profile share prints once, naming both. A
problem that deployments on different bindings share prints once for each
binding, so kcmd profiles shows it under each profile.

Push now also warns that default is unbound when the model file's own
bindings are incomplete and every deployment names a profile, and kcmd profiles prints the warning under default. A selected deployment's profile
now gets its warning about SQL kcmd cannot read from the profile check, as
under --no-deployment, so a push that stops before that deployment's checks
still prints it.

Main's today's-path call to validateDeployments in modelFileBindingErrors
goes, with the joinsChecked option and unboundInline's joins parameter.
Since the previous PR, every model that lists deployments pushes in two
phases, so that call checked no deployment.

On a two-phase push, the BigQuery source probe now runs in the location of the
graph's dataset, where the graph's DDL runs. When a probe fails there and a
second probe with no location finds the table in another location, the error
names both locations. When push cannot read the dataset's location, the probe
lets BigQuery choose, as before.

On main, a plain push of a model that lists deployments deploys a Spanner
deployment whose model file binds a BigQuery table or a table in another Spanner
database. The Spanner DDL names each table without its database, so the graph
reads the target database's table of that name. Such a push now fails before
any write. A push that keeps today's path does not run the check. That path
still deploys such a graph for a vanilla model whose GOOGLE block lists
deploymentTargets, and for a legacy wrapper with deployment_target:. Before
this PR, a BigQuery table in another location failed the DDL dry run with
BigQuery's own message. It now fails the source probe with an error that names
its location.

The runtime's comments in store.ts no longer say push accepts a table outside
the store. store_agreement's 'Spanner beside BigQuery' case now expects push and
the report to refuse the BigQuery deployment that reads a Spanner table, and
its vanilla cases bind profile prod to a table in a second Spanner database.
Main's Cloud SQL test of the inline bindings now expects the model file's
dialect error. The table check refuses its BigQuery deployment before any
metric check, so its metric no longer tested the lookup.

Points to check:

  1. A named profile is read alone. The completeness check runs earlier and
    requires a source in the profile for every concrete entity, so no entity
    falls back to an unchecked model-file source.
  2. The second probe runs only after the first fails, and its location counts
    only when it differs from the dataset's.
  3. The source is trimmed before the comparison, since a profile file's
    source: | block ends in a newline.
  4. profiled applies the profile and prunes it, as deploymentPlan does, so
    the metric rules skip exactly the metrics the deployment does not deploy
    and read the keys the profile states.

…the profile it names

The profile check now also gives the warning about SQL kcmd cannot read
in the profiles of the deployments push deploys, so it prints even when
push stops at an earlier check, as under --no-deployment.
@feixufeixu
feixufeixu requested a review from merr1988 October 24, 2026 20:38
@feixufeixu
feixufeixu added this pull request to stack #565 October 24, 2026 20:38
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