Skip to content

feat(engine): config-group misplacement guard — reject incoherent args + pinned schema (C5)#923

Merged
hugocorreia90 merged 1 commit into
mainfrom
feat/engine/c5-misplacement-guard
Jun 18, 2026
Merged

feat(engine): config-group misplacement guard — reject incoherent args + pinned schema (C5)#923
hugocorreia90 merged 1 commit into
mainfrom
feat/engine/c5-misplacement-guard

Conversation

@hugocorreia90

Copy link
Copy Markdown
Contributor

What

The buildable remainder of C5. Most of C5 — "a model's target schema derives from its location/metadata" — was already delivered by C4: config groups derive a member's schema from schema_template + per-model [args], and enforce = true hard-blocks an override for enforced groups. This PR adds the one piece that was missing: the misplacement guard for the incoherent config the plan calls "a misplaced model fails compile."

A group's [args] exist solely to fill its schema_template. If a member also pins its own target.schema, the pin wins (sidecar > group), so the template is bypassed and the args are dead. That's never a valid override — it usually masks a routing mistake ("I thought [args] routed this model, but the pin sends it elsewhere"). It now fails the load:

# group marts: schema_template = "mart_{region}"
group = "marts"
[target]
schema = "escape"     # pins schema → bypasses the template
[args]
region = "emea"       # ...so this can never route anything → ERROR

ModelError::GroupArgsWithPinnedSchema. Pin a schema or supply args, not both.

How

  • Detected in the shared resolve_model_config chokepoint, next to the existing enforce check — so it covers both .sql and .rocky for free (.rocky regression included). No ModelConfig churn, no new warning channel; a load error fails compile, the same path GroupOverride already uses.
  • Group-schema resolution is now lazy: a model that pins its own schema skips the template entirely. Without this, a legitimate pin-without-args override would error on an unfilled {region} placeholder for a template it never uses. ([args] is template-only — verified no other consumer — and unreleased, so no existing project changes behavior.)

Allowed cases (unchanged)

  • Pin a schema, no args → override (template bypassed).
  • Supply args, no pin → route via template.
  • Enforced group + pin → already GroupOverride.

Only the contradiction (group with a template + args + pin) is rejected. Two existing tests that encoded the now-forbidden args+pin pattern were updated to the coherent override (pin, no args).

Verification

cargo test --all-features -p rocky-core -p rocky-compiler green (incl. the guard, the allowed companion, and the .rocky regression); cargo fmt --check + clippy --all-targets --all-features clean.

🤖 Generated with Claude Code

…rs (C5 misplacement guard)

A config group's `[args]` exist solely to fill its `schema_template`. A
member that also pins its own `target.schema` overrides the group
(sidecar > group), so the template is bypassed and the args are dead —
an incoherent config that usually masks a routing mistake ("I thought
[args] routed this model, but the pin sends it elsewhere"). This now
fails the load with `ModelError::GroupArgsWithPinnedSchema`.

Most of C5 (schema derived from metadata; hard-block override for
enforced groups) was already delivered by C4's config groups + enforce.
This adds the one remaining guard — the args+pin contradiction.

- Detected in the shared `resolve_model_config` chokepoint next to the
  `enforce` check, so it covers both `.sql` and `.rocky` for free.
- Group-schema resolution is now lazy: a model that pins its own schema
  skips the template entirely, so a legitimate pin-without-args override
  no longer errors on an unfilled placeholder it never uses.
- No ModelConfig churn, no new warning channel — a load error fails
  compile, same path as `GroupOverride`.

Allowed cases unchanged: pin a schema with no args (override), or supply
args with no pin (route via template). Only the contradiction is rejected.
@hugocorreia90 hugocorreia90 merged commit 9b1d405 into main Jun 18, 2026
13 checks passed
@hugocorreia90 hugocorreia90 deleted the feat/engine/c5-misplacement-guard branch June 18, 2026 02:37
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