Skip to content

[Feature] - Validate config keys for misspellings #370

Description

@sdurry

Summary

Add a new CLI command check-config-keys that scans a dbt project's dbt_project.yml and schema YAML files, identifies both property keys and config keys not present in the Fusion JSON schema, and suggests the closest valid key where a misspelling is likely.

This command acts as a pre-check before running autofix — surfacing human errors (typos, wrong separators) that deterministic fixes can't catch on their own.

Motivation

The manual_fixes/misspelled_config_keys.md guidance today is purely documentation for AI agents. This feature brings that logic into the CLI itself, giving all users a fast, deterministic tool to catch config key mistakes before they cause Fusion parse failures.

Proposed command

dbt-autofix check-config-keys [--path PATH] [--json]

Example output:

myproject/dbt_project.yml:14  unknown key 'materailized' — did you mean 'materialized'?
myproject/models/staging/_schema.yml:7  unknown key 'pre_hook' — did you mean 'pre-hook'?
myproject/models/staging/_schema.yml:9  unknown key 'desciption' — did you mean 'description'?
myproject/models/marts/_schema.yml:22  unknown key 'snowflake_warehose' — did you mean 'snowflake_warehouse'?
myproject/models/marts/_schema.yml:31  unknown key 'custom_owner' — no close match found (consider moving to meta:)

Design

Schema source: Fusion CDN schemas (same source as the deprecations command), via the existing SchemaSpecs class in retrieve_schemas.py. No new schema fetching infrastructure needed.

Similarity algorithm: Two-stage normalized Levenshtein

  1. Normalize first — strip + prefix, unify -/_ separators → check for exact match (catches separator confusion for free, zero false positives)
  2. Levenshtein distance with proportional threshold (max(1, len(key) // 7)) on the remainder — short keys require near-exact match, long keys get more slack

Key sets checked per node in yml files (two layers):

  • Property keys (top-level node keys like description, name, constraints) → SchemaSpecs.yaml_specs_per_node_type[node_type].allowed_properties
  • Config block keys (keys inside config:) → SchemaSpecs.yaml_specs_per_node_type[node_type].allowed_config_fields
  • dbt_project.yml config keysSchemaSpecs.dbtproject_specs_per_node_type[node_type].allowed_config_fields_dbt_project

Relationship to existing work

This feature fully addresses #9. That issue identified that misspelling detection is currently limited to a hardcoded dict in src/dbt_autofix/refactors/constants.py:

  • COMMON_PROPERTY_MISSPELLINGS — only catches 4 variants of description
  • COMMON_CONFIG_MISSPELLINGS — only catches post-hook/pre-hook separator confusion

These are used in the deprecations command today: if a key matches the hardcoded dict it gets renamed, otherwise it is silently moved to meta. The new command replaces the guesswork with a dynamic, schema-driven similarity check across the full set of valid keys.

Future opportunity: upgrade the deprecations command

Once the similarity algorithm exists as a standalone module (key_similarity.py), the deprecations changeset logic in dbt_schema_yml.py and dbt_sql.py could be upgraded to use it instead of the static dicts — making autofix itself smarter about what it renames vs. what it moves to meta. This is intentionally out of scope for this issue but is a natural follow-on.

Implementation plan

Phase 1 — Foundation (parallel)

  • 1B src/dbt_autofix/key_similarity.py — pure similarity functions (normalize_key, levenshtein_distance, find_closest_match)
  • 1C tests/unit_tests/test_key_similarity.py — unit tests (exact match after normalization, transpositions, separator confusion, short-key false-positive guard, long keys)

Phase 2 — Scanner (depends on Phase 1)

  • 2A src/dbt_autofix/config_key_checker.py — walks project files, checks both property keys and config block keys against SchemaSpecs, returns (file_path, line_number, unknown_key, suggestion | None). Uses ruamel.yaml for line number preservation.
  • 2B tests/unit_tests/test_config_key_checker.py — unit tests using MockSchemaSpecs pattern from test_refactor.py

Phase 3 — CLI wiring (depends on Phase 2)

  • 3A Add @app.command(name="check-config-keys") to src/dbt_autofix/main.py. Instantiates SchemaSpecs, accepts --path/-p and --json/-j.

Phase 4 — Integration test (depends on Phase 3)

  • 4A Fixture project tests/integration_tests/dbt_projects/project_misspelled_keys/ with deliberate misspellings across both property keys and config keys
  • 4B Integration test asserting expected findings

Dependency graph

1B ──► 2A ──► 3A ──► 4A ──► 4B
1C (parallel with 1B)
2B (parallel with 2A, uses MockSchemaSpecs)

Out of scope

  • Auto-fixing the misspellings (that remains a manual or AI-assisted step)
  • Validating value correctness (e.g. invalid enum values for materialized)
  • Upgrading the deprecations command to use the new similarity algorithm (tracked as a future follow-on above)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions