Skip to content

fix(engine): correct invalid-JSON error type and mis-targeted sync test - #193

Merged
cryptoxdog merged 2 commits into
mainfrom
claude/cognitive-engine-graphs-pr-jshyk3
Aug 5, 2026
Merged

fix(engine): correct invalid-JSON error type and mis-targeted sync test#193
cryptoxdog merged 2 commits into
mainfrom
claude/cognitive-engine-graphs-pr-jshyk3

Conversation

@cryptoxdog

Copy link
Copy Markdown
Collaborator

Summary

Fixes the two pre-existing engine bugs surfaced (and flagged, not fixed) during the SonarCloud remediation in #191. Small, focused, behavior-correcting — 4 files.

Bug 1 — invalid-JSON path raised TypeError instead of a real error

engine/security/P2_9_llm_schemas.py and engine/security/_5_llm_security.py constructed a pydantic ValidationError from a plain string on the JSON-parse branch. In pydantic v2 ValidationError is not string-constructible (needs from_exception_data), so validate_llm_json("not json", …) raised TypeError while building the error — masking the actual "invalid JSON" condition.

  • Raise ValueError on the JSON-parse failure. pydantic.ValidationError subclasses ValueError, so any caller doing broad except ValueError still catches schema-shape failures too — no behavior regression.
  • Schema-shape failures continue to raise pydantic ValidationError via model_validate (e.g. the destructive-Cypher validator), unchanged.
  • Dropped the now-unused ValidationError import in P2_9_llm_schemas.py.

Bug 2 — test asserted a method that doesn't exist

tests/integration/test_sync_handler.py::test_sync_unknown_entity_type_raises called SyncGenerator.resolve_endpoint(...), which does not exist; the test only passed because pytest.raises(Exception/AttributeError) swallowed the resulting AttributeError. It never exercised the behavior its docstring claims ("RULE 3: unknown entity_type is rejected").

  • Rewritten to exercise the real rejection path: handle_sync resolves entity_type to a declared sync endpoint and raises the engine ValidationError ("No sync endpoint for entity type …") when none matches. That rejection happens during endpoint resolution, before any Neo4j access, so the test uses the real domain loader + a mock driver (no testcontainers needed).
  • test_invalid_json updated to assert the corrected ValueError (was asserting the buggy TypeError).

Validation (CI-pinned toolchain)

  • ruff check / ruff format --check ✅ · mypy engine/ ✅ (139 files) · tools/contract_scanner.py ✅ no violations
  • Unit suite: 721 passed, 4 skipped · touched files (test_algorithmic_upgrades.py, test_sync_handler.py): 30 passed, 2 skipped (the 2 skips are the Neo4j-only sync tests; the new RULE-3 test runs without Neo4j by design)

Generated by Claude Code

Two pre-existing bugs surfaced during the SonarCloud remediation (#191):

1. engine/security/{P2_9_llm_schemas,_5_llm_security}.py raised
   pydantic ValidationError with a plain string on the JSON-parse path.
   In pydantic v2 ValidationError is not string-constructible, so the
   invalid-JSON branch raised TypeError instead of a meaningful error.
   Raise ValueError (which pydantic.ValidationError subclasses, so
   broad-catch callers are unaffected); schema-shape failures still raise
   pydantic ValidationError via model_validate. Drop the now-unused import.

2. tests/integration/test_sync_handler.py asserted a non-existent
   SyncGenerator.resolve_endpoint and only passed because pytest.raises
   swallowed the AttributeError. Rewrite it to exercise the real RULE 3
   path: handle_sync rejects an unknown entity_type with ValidationError
   ("No sync endpoint for entity type") during endpoint resolution,
   before any Neo4j access (mock driver + real domain loader).

test_invalid_json updated to assert the corrected ValueError.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01USEi3CurG9BEbx5bTHHGMx
Copilot AI lite review requested due to automatic review settings August 5, 2026 01:06
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

PR reviewable size is within recommended limits

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

L9 Audit Harness Report

  • Generated: 2026-08-05T01:14:26.308676+00:00
  • Repo root: /home/runner/work/Cognitive.Engine.Graphs/Cognitive.Engine.Graphs
  • Overall result: ✅ PASSED
  • Exit code: 0

Step Results

Step Status Exit Code Notes
Architecture Audit ✅ Passed 0
Spec Coverage ✅ Passed 0
Contract Wiring ✅ Passed 0

Architecture Audit Findings

Severity Count
🔴 CRITICAL 0
🟠 HIGH 0
🟡 MEDIUM 25
🔵 LOW 0

See artifacts/audit_report.md for full details.

Spec Coverage

  • ✅ Implemented: 37
  • ⚠️ Partial: 9
  • ❌ Missing: 0
  • Total features: 46
Category Implemented Partial Missing Total
gates 10 0 0 10
scoring 7 0 0 7
v1.1_node 2 0 0 2
v1.1_edge 2 0 0 2
v1.1_action 0 2 0 2
v1.1_scoring 1 1 0 2
action_handler 0 6 0 6
gds_algorithm 5 0 0 5
research_pattern 10 0 0 10

See artifacts/coverage_report.md for full details.

Next Steps

All checks passed. Safe to merge.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes two pre-existing engine issues: (1) invalid-JSON handling in LLM helpers raising TypeError due to incorrect pydantic.ValidationError construction in Pydantic v2, and (2) a sync test that was asserting a non-existent method instead of exercising the real unknown-entity-type rejection path.

Changes:

  • Replace invalid ValidationError("...") construction on JSON parse failures with a proper ValueError (preserving schema-validation ValidationError behavior via model_validate).
  • Update LLM JSON validation tests to assert ValueError with an “invalid JSON” message.
  • Rewrite the “unknown entity_type” sync test to call handle_sync and assert the real engine.handlers.ValidationError rejection path.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
tests/test_algorithmic_upgrades.py Updates invalid-JSON expectation from TypeError to ValueError with message match.
tests/integration/test_sync_handler.py Replaces a non-exercising test (nonexistent method) with an async handler-based assertion of unknown entity type rejection.
engine/security/P2_9_llm_schemas.py Fixes invalid-JSON error path to raise ValueError instead of incorrectly constructing Pydantic ValidationError.
engine/security/_5_llm_security.py Fixes invalid-JSON error path to raise ValueError (but docstring still needs to reflect this).

Comment on lines 156 to +160
logger.exception("LLM returned invalid JSON")
raise ValidationError(f"LLM output is not valid JSON: {e}")
# pydantic's ValidationError is not string-constructible in v2; raise a
# ValueError (its superclass) so the JSON-parse failure surfaces cleanly.
msg = f"LLM output is not valid JSON: {e}"
raise ValueError(msg) from e
…utput

Addresses PR review: the JSON-parse path now raises ValueError (not
pydantic ValidationError), so the docstring Raises section is updated to
reflect the real public contract.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01USEi3CurG9BEbx5bTHHGMx
Copilot AI review requested due to automatic review settings August 5, 2026 01:14
@sonarqubecloud

sonarqubecloud Bot commented Aug 5, 2026

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Suppressed comments (1)

tests/integration/test_sync_handler.py:55

  • handle_sync() enforces TENANT_ALLOWLIST before endpoint resolution. If the environment (CI/dev) sets a allowlist that doesn’t include plasticos, this test will fail with a different ValidationError than expected. Consider pinning TENANT_ALLOWLIST via monkeypatch for determinism, and call init_dependencies with keyword args (most tests do; e.g. tests/integration/test_handlers.py:67).
    from engine.handlers import ValidationError, handle_sync, init_dependencies
    from engine.state import get_state

    get_state().reset()
    init_dependencies(AsyncMock(), domain_loader)

@cryptoxdog
cryptoxdog merged commit 5b96ae5 into main Aug 5, 2026
53 checks passed
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.

3 participants