Skip to content

Conversation

@ogenstad
Copy link
Contributor

@ogenstad ogenstad commented Jan 2, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Removed spurious deprecation warnings for text attribute configuration fields.
  • Changes

    • GraphQL API fields now required instead of optional, ensuring stricter data validation and response consistency.

✏️ Tip: You can customize this high-level summary in your review settings.

ogenstad and others added 9 commits December 30, 2025 16:22
…olation

Move too many statement violations to single file
…7967)

* feat: make DiffTreeSummary GraphQL count fields non-optional
* fix warnings for deprecated attr regex/min/max

* handle text param reconcile earlier in load

* also handle loading legacy schema from db

* add changelog
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 2, 2026

Walkthrough

This pull request refactors Text attribute schema handling by moving validation logic from TextAttributeSchema to SchemaBranch. It removes a model_validator method and introduces three new reconciliation methods that synchronize deprecated top-level fields (regex, min_length, max_length) with new TextAttributeParameters during schema loading and validation. Additionally, GraphQL schema fields are hardened to non-nullable across multiple types, DiffTreeSummary count fields are made required, type annotations are systematically added to test fixtures, and test cases are updated to reflect the new parameters-based configuration approach.

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.32% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes a merge operation between two branches with conflict resolution, which matches the PR's core objective.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the group/backend Issue related to the backend (API Server, Git Agent) label Jan 2, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 2, 2026

CodSpeed Performance Report

Merging #8010 will not alter performance

Comparing pog-stable-to-release-1.7-20260102b (1458343) with release-1.7 (72f7b3d)

Summary

✅ 12 untouched

@ajtmccarty ajtmccarty marked this pull request as ready for review January 2, 2026 16:11
@ajtmccarty ajtmccarty requested a review from a team as a code owner January 2, 2026 16:11
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72f7b3d and 1458343.

📒 Files selected for processing (13)
  • backend/infrahub/core/schema/attribute_schema.py
  • backend/infrahub/core/schema/schema_branch.py
  • backend/infrahub/graphql/app.py
  • backend/infrahub/graphql/queries/diff/tree.py
  • backend/tests/conftest.py
  • backend/tests/integration/schema_lifecycle/test_attribute_parameters_update.py
  • backend/tests/unit/core/schema_manager/test_manager_schema.py
  • backend/tests/unit/core/test_attribute.py
  • backend/tests/unit/core/test_schema.py
  • changelog/7778.changed.md
  • changelog/7995.fixed.md
  • pyproject.toml
  • schema/schema.graphql
💤 Files with no reviewable changes (2)
  • backend/infrahub/core/schema/attribute_schema.py
  • backend/tests/integration/schema_lifecycle/test_attribute_parameters_update.py
🧰 Additional context used
📓 Path-based instructions (8)
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Follow Markdown coding standards defined in dev/guidelines/markdown.md

Files:

  • changelog/7995.fixed.md
  • changelog/7778.changed.md
{backend/infrahub/core/schema/generated/**,backend/infrahub/core/protocols.py,frontend/app/src/shared/api/graphql/generated/**,frontend/app/src/shared/api/rest/types.generated.ts,schema/schema.graphql,schema/openapi.json}

📄 CodeRabbit inference engine (AGENTS.md)

Do not edit generated files in backend/infrahub/core/schema/generated/, backend/infrahub/core/protocols.py, frontend/app/src/shared/api/graphql/generated/, frontend/app/src/shared/api/rest/types.generated.ts, schema/schema.graphql, and schema/openapi.json

Files:

  • schema/schema.graphql
**/*.py

📄 CodeRabbit inference engine (.github/instructions/python-docstring.instructions.md)

**/*.py: Always use triple quotes (""") for Python docstrings
Follow Google-style docstring format for Python docstrings
Include brief one-line description in Python docstrings when applicable
Include detailed description in Python docstrings when applicable
Include Args/Parameters section without typing in Python docstrings when applicable
Include Returns section in Python docstrings when applicable
Include Raises section in Python docstrings when applicable
Include Examples section in Python docstrings when applicable

**/*.py: Use type hints for all function parameters and return values in Python
Use Async whenever possible in Python
Use async def for asynchronous functions in Python
Use await for asynchronous calls in Python
Use Pydantic models for dataclasses in Python
Use ruff and mypy for type checking and code validation in Python

Use ruff and mypy to validate and lint Python files

Files:

  • backend/tests/unit/core/schema_manager/test_manager_schema.py
  • backend/infrahub/graphql/queries/diff/tree.py
  • backend/infrahub/graphql/app.py
  • backend/tests/unit/core/test_attribute.py
  • backend/infrahub/core/schema/schema_branch.py
  • backend/tests/unit/core/test_schema.py
  • backend/tests/conftest.py
backend/tests/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run backend tests with pytest or via invoke tasks

Test files should mirror source structure: infrahub/core/node.py should have corresponding test at tests/unit/core/test_node.py

Files:

  • backend/tests/unit/core/schema_manager/test_manager_schema.py
  • backend/tests/unit/core/test_attribute.py
  • backend/tests/unit/core/test_schema.py
  • backend/tests/conftest.py
backend/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

backend/**/*.py: Follow Python coding standards defined in dev/guidelines/backend/python.md
Use type hints for Python in backend code

backend/**/*.py: Use async/await for all I/O operations in Python code
Type hint all function parameters and return values in Python code
Use Pydantic models for data structures in Python code

Files:

  • backend/tests/unit/core/schema_manager/test_manager_schema.py
  • backend/infrahub/graphql/queries/diff/tree.py
  • backend/infrahub/graphql/app.py
  • backend/tests/unit/core/test_attribute.py
  • backend/infrahub/core/schema/schema_branch.py
  • backend/tests/unit/core/test_schema.py
  • backend/tests/conftest.py
backend/infrahub/graphql/**/*.py

📄 CodeRabbit inference engine (backend/AGENTS.md)

Ask for review approval before making core schema definition changes or adding new GraphQL mutations/queries

Files:

  • backend/infrahub/graphql/queries/diff/tree.py
  • backend/infrahub/graphql/app.py
backend/infrahub/**/*.py

📄 CodeRabbit inference engine (backend/AGENTS.md)

backend/infrahub/**/*.py: Never use unparameterized Cypher queries - always use parameterized queries to prevent injection
Never block the event loop with synchronous I/O operations

Files:

  • backend/infrahub/graphql/queries/diff/tree.py
  • backend/infrahub/graphql/app.py
  • backend/infrahub/core/schema/schema_branch.py
{pyproject.toml,uv.lock}

📄 CodeRabbit inference engine (.github/instructions/tooling.instructions.md)

Use uv to manage the Python project and its dependencies

Files:

  • pyproject.toml
🧠 Learnings (7)
📚 Learning: 2025-12-26T09:03:55.145Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-26T09:03:55.145Z
Learning: Ask before making GraphQL schema modifications

Applied to files:

  • schema/schema.graphql
📚 Learning: 2025-12-26T09:04:09.935Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-26T09:04:09.935Z
Learning: Applies to backend/infrahub/graphql/**/*.py : Ask for review approval before making core schema definition changes or adding new GraphQL mutations/queries

Applied to files:

  • schema/schema.graphql
📚 Learning: 2025-12-26T09:03:55.145Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-26T09:03:55.145Z
Learning: Applies to {backend/infrahub/core/schema/generated/**,backend/infrahub/core/protocols.py,frontend/app/src/shared/api/graphql/generated/**,frontend/app/src/shared/api/rest/types.generated.ts,schema/schema.graphql,schema/openapi.json} : Do not edit generated files in `backend/infrahub/core/schema/generated/`, `backend/infrahub/core/protocols.py`, `frontend/app/src/shared/api/graphql/generated/`, `frontend/app/src/shared/api/rest/types.generated.ts`, `schema/schema.graphql`, and `schema/openapi.json`

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-26T09:03:55.145Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-26T09:03:55.145Z
Learning: Applies to backend/**/*.py : Follow Python coding standards defined in `dev/guidelines/backend/python.md`

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-26T09:03:55.145Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-26T09:03:55.145Z
Learning: Applies to backend/**/*.py : Use type hints for Python in backend code

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-26T09:04:09.935Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-26T09:04:09.935Z
Learning: Applies to backend/**/*.py : Use async/await for all I/O operations in Python code

Applied to files:

  • backend/infrahub/graphql/app.py
📚 Learning: 2025-12-01T22:15:40.243Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: .github/instructions/python.instructions.md:0-0
Timestamp: 2025-12-01T22:15:40.243Z
Learning: Applies to **/*.py : Use `await` for asynchronous calls in Python

Applied to files:

  • backend/infrahub/graphql/app.py
🧬 Code graph analysis (4)
backend/tests/unit/core/schema_manager/test_manager_schema.py (1)
backend/infrahub/core/schema/schema_branch.py (3)
  • load_schema (566-598)
  • get (324-357)
  • duplicate (292-301)
backend/tests/unit/core/test_attribute.py (1)
backend/infrahub/core/schema/attribute_parameters.py (1)
  • TextAttributeParameters (28-58)
backend/infrahub/core/schema/schema_branch.py (1)
backend/infrahub/core/schema/attribute_parameters.py (2)
  • NumberPoolParameters (146-173)
  • TextAttributeParameters (28-58)
backend/tests/unit/core/test_schema.py (3)
backend/infrahub/core/schema/__init__.py (1)
  • SchemaRoot (63-155)
backend/infrahub/core/schema/attribute_schema.py (1)
  • TextAttributeSchema (234-248)
backend/infrahub/core/schema/attribute_parameters.py (1)
  • TextAttributeParameters (28-58)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (16)
backend/infrahub/graphql/app.py (1)

167-177: LGTM! Clean simplification of async handling.

The removal of explicit type casts in favor of direct await/return is more concise and equally type-safe. The isawaitable check ensures the response is handled correctly in both async and sync cases.

pyproject.toml (1)

743-748: LGTM! More specific linter configuration.

Moving the PLR0915 (Too many statements) ignore from the global backend/tests/*.py pattern to a specific file (backend/tests/db_snapshot.py) improves code quality enforcement by not suppressing warnings unnecessarily across all test files.

changelog/7778.changed.md (1)

1-1: LGTM! Accurate changelog entry.

The changelog entry correctly documents the breaking change to DiffTreeSummary GraphQL type, making count fields non-optional. This aligns with the code changes in backend/infrahub/graphql/queries/diff/tree.py.

changelog/7995.fixed.md (1)

1-1: LGTM! Accurate changelog entry for warning fix.

The changelog entry correctly documents the fix for deprecation warnings on attribute schema fields (regex, min_length, max_length), ensuring warnings only appear when these fields are actually used. This aligns with the Text attribute schema refactoring mentioned in the PR summary.

backend/infrahub/graphql/queries/diff/tree.py (2)

149-149: No action needed. The field is always provided by the summary model.

The underlying DiffSummaryCounters model initializes num_unchanged with a default value of 0, and DiffSummaryCounters.from_graph() applies an or 0 fallback when creating instances from query results. When summary.model_dump(exclude={"from_time", "to_time"}) is called at line 547, the num_unchanged field is always present with an integer value. If the summary result is None, the resolver returns early without instantiating DiffTreeSummary. The change to required=True is valid.


63-66: Verified: Count fields are always initialized in source models, making the required=True change safe.

The underlying data models (EnrichedDiffRoot, EnrichedDiffNode, EnrichedDiffAttribute, etc.) inherit from BaseSummary in backend/infrahub/core/diff/model/path.py, where all four count fields are initialized with default=0:

  • num_added: int = field(default=0, kw_only=True)
  • num_updated: int = field(default=0, kw_only=True)
  • num_removed: int = field(default=0, kw_only=True)
  • num_conflicts: int = field(default=0, kw_only=True)

These fields are guaranteed to be non-None integers in the source models, so making them required in the GraphQL schema is justified and reflects the actual data guarantees.

backend/tests/unit/core/schema_manager/test_manager_schema.py (1)

390-459: Text attribute reconciliation test correctly exercises both configuration styles

The test cleanly covers both directions of reconciliation (parameters-only and top-level-only) and asserts that regex/min_length/max_length are synchronized between deprecated fields and TextAttributeParameters after load_schema. This is a good, focused regression test for the new reconciliation logic.

backend/tests/unit/core/test_attribute.py (1)

317-345: Updated text-parameter validation test aligns with TextAttributeParameters usage

Constructing the NodeSchema with AttributeSchema(..., parameters=TextAttributeParameters(...)) and driving validation through Node.init/new gives realistic coverage of min_length, max_length, and regex behavior. The checks look consistent with the parameter model and the rest of this file’s validation tests.

backend/tests/unit/core/test_schema.py (1)

127-164: Warning test cases correctly capture non-deprecated parameter usage

These two SchemaWarningTestCaseData entries precisely assert that using TextAttributeParameters for min_length/max_length and regex does not produce deprecation warnings, which matches SchemaRoot.gather_warnings() semantics. This is a useful guard against regressions as you phase out the legacy top-level fields.

backend/infrahub/core/schema/schema_branch.py (5)

57-57: LGTM!

The import is correctly updated to include TextAttributeParameters needed for the new reconciliation logic.


504-512: LGTM!

The _text_attr_needs_reconciliation method correctly detects when deprecated top-level fields differ from parameter-based fields, enabling targeted updates only when necessary.


514-538: LGTM!

The reconciliation logic correctly implements bidirectional sync with parameters taking precedence. The pattern is clear and consistently applied for all three fields (regex, min_length, max_length).


566-573: LGTM!

The reconciliation is correctly positioned before the merge loop, ensuring that deprecated Text attribute fields are synchronized with parameters before items are processed and cached.


606-614: LGTM!

The reconciliation call in process_pre_validation correctly handles schemas loaded from the database, ensuring backward compatibility with schemas that may have been stored with only deprecated top-level fields.

schema/schema.graphql (1)

6340-6343: Generated file changes look consistent.

Per coding guidelines, schema/schema.graphql is a generated file. The changes making count fields (num_added, num_conflicts, num_removed, num_updated, num_unchanged) non-nullable across the Diff-related types are consistent with the backend changes in DiffSummaryCounts and DiffTreeSummary mentioned in the summary.

Also applies to: 6356-6359, 6392-6395, 6404-6407, 6421-6426, 6441-6447

backend/tests/conftest.py (1)

127-127: Excellent systematic type annotation improvements!

The systematic addition of explicit type hints across all pytest fixtures significantly improves type safety and code maintainability. The changes correctly:

  • Add None type annotations for fixture dependencies that perform side effects
  • Specify concrete return types (SchemaBranch, SchemaRoot, Branch, etc.)
  • Include proper Generator type parameters
  • Add parameter type hints (str, int, pytest.FixtureRequest)
  • Convert tmpdir_factory.mktemp() result to Path for type consistency (line 488)

These changes align perfectly with the coding guidelines requiring type hints for all function parameters and return values.

Also applies to: 179-181, 219-219, 274-276, 295-295, 309-309, 331-333, 349-349, 363-363, 375-375, 393-393, 419-419, 433-433, 448-448, 453-455, 479-479, 488-488, 501-501, 544-544, 592-594, 664-664, 690-690, 747-747, 753-753, 844-844, 904-904, 913-913, 920-922, 1017-1017, 1023-1023, 1072-1072, 1279-1279, 1326-1326, 1334-1334, 1441-1441, 1497-1497, 1564-1565, 1658-1660, 1738-1738

Comment on lines +540 to +564
def _reconcile_text_attribute_parameters(self, schema: SchemaRoot | None = None) -> None:
"""Reconcile regex, min_length, max_length between deprecated fields and parameters for Text attributes.
Args:
schema: If provided, reconcile incoming schema data before merging.
If None, reconcile already-loaded schemas (e.g., from database).
"""
if schema:
# Incoming schema: modify in place
for item in schema.nodes + schema.generics:
for attr in item.attributes:
self._reconcile_text_attr(attr)
return

# Loaded schemas: need to duplicate before modifying
for name in self.all_names:
node = self.get(name=name, duplicate=False)

if not any(self._text_attr_needs_reconciliation(attr) for attr in node.attributes):
continue

node = node.duplicate()
for attr in node.attributes:
self._reconcile_text_attr(attr)
self.set(name=name, schema=node)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if extensions can contain attributes that might need reconciliation
rg -n "class NodeExtensionSchema" -A 30

Repository: opsmill/infrahub

Length of output: 2489


🏁 Script executed:

#!/bin/bash
# Check the schema root structure to understand extensions
rg -n "class SchemaRoot" -A 30

Repository: opsmill/infrahub

Length of output: 2547


🏁 Script executed:

#!/bin/bash
# Check load_schema to understand extension processing
rg -n "def load_schema" -A 100 | head -150

Repository: opsmill/infrahub

Length of output: 18289


🏁 Script executed:

#!/bin/bash
# Find BaseNodeExtensionSchema definition
rg -n "class BaseNodeExtensionSchema" -A 20

Repository: opsmill/infrahub

Length of output: 1646


🏁 Script executed:

#!/bin/bash
# Find the load_schema method in schema_branch.py
rg -n "def load_schema" backend/infrahub/core/schema/schema_branch.py -A 60 | head -100

Repository: opsmill/infrahub

Length of output: 2924


🏁 Script executed:

#!/bin/bash
# Check how extensions are used/processed after load_schema
rg -n "\.extensions\." backend/infrahub/core/schema/schema_branch.py

Repository: opsmill/infrahub

Length of output: 118


Reconcile Text attributes in schema extensions.

Extensions can contain Text attributes with deprecated fields (regex, min_length, max_length), but _reconcile_text_attribute_parameters only processes schema.nodes and schema.generics when called with a schema argument. The method should also reconcile schema.extensions.nodes to ensure consistent handling across all schema components.

Code location

Lines 547-552 in _reconcile_text_attribute_parameters:

if schema:
    # Incoming schema: modify in place
    for item in schema.nodes + schema.generics:
        for attr in item.attributes:
            self._reconcile_text_attr(attr)
    return

Should also include schema.extensions.nodes.

🤖 Prompt for AI Agents
In backend/infrahub/core/schema/schema_branch.py around lines 540 to 564, the
incoming-schema branch only reconciles schema.nodes and schema.generics but
omits schema.extensions.nodes, so Text attributes in extensions won't be
updated; update the code path that handles a provided schema to also iterate
over schema.extensions.nodes (e.g., include schema.extensions.nodes in the
iteration or extend the list) and call self._reconcile_text_attr on each
attribute there before returning.

@ajtmccarty ajtmccarty merged commit 00c00dc into release-1.7 Jan 2, 2026
42 checks passed
@ajtmccarty ajtmccarty deleted the pog-stable-to-release-1.7-20260102b branch January 2, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

group/backend Issue related to the backend (API Server, Git Agent)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants