This is an automated email from the ASF dual-hosted git repository.

imbajin pushed a commit to branch goal-scan
in repository https://gitbox.apache.org/repos/asf/hugegraph-ai.git

commit a8d7b2e306c7bf8d5e8209e81aa5630db3ce90ce
Author: imbajin <[email protected]>
AuthorDate: Sun May 31 11:52:13 2026 +0800

    fix(llm): preserve extracted graph value types
    
    - stop stringifying property graph values after extraction
    - add extraction-to-commit round-trip contract coverage
    - update code-scan ledgers for CS-013
---
 .workflow/code-scan/code-scan-state.json           |  6 +-
 .../code-scan/reports/final-code-scan-report.md    |  3 +-
 .workflow/code-scan/reports/issues.md              |  6 +-
 .workflow/code-scan/reports/test-quality-ledger.md |  3 +-
 .../operators/llm_op/property_graph_extract.py     |  3 -
 .../test_commit_to_hugegraph_load_into_graph.py    | 65 +++++++++++++++++++++-
 .../llm_op/test_property_graph_extract.py          |  7 +--
 7 files changed, 74 insertions(+), 19 deletions(-)

diff --git a/.workflow/code-scan/code-scan-state.json 
b/.workflow/code-scan/code-scan-state.json
index 19867c27..16845f25 100644
--- a/.workflow/code-scan/code-scan-state.json
+++ b/.workflow/code-scan/code-scan-state.json
@@ -58,7 +58,8 @@
     "CS-001",
     "CS-002",
     "CS-004",
-    "CS-008"
+    "CS-008",
+    "CS-013"
   ],
   "files_touched": [
     "docs/specs/2026-05-31-hugegraph-ai-code-scan-design.md",
@@ -89,7 +90,6 @@
     
"hugegraph-llm/src/tests/operators/hugegraph_op/test_commit_to_hugegraph.py",
     
"hugegraph-llm/src/tests/operators/hugegraph_op/test_commit_to_hugegraph_load_into_graph.py",
     "hugegraph-llm/src/tests/operators/index_op/test_vector_index_query.py",
-    "hugegraph-llm/src/tests/operators/llm_op/test_property_graph_extract.py",
     "hugegraph-python-client/src/tests/api/test_auth_routing.py",
     "hugegraph-python-client/src/tests/api/test_graph.py",
     "hugegraph-python-client/src/tests/api/test_gremlin.py",
@@ -125,5 +125,5 @@
     "uv run ruff check <edited-python-files>",
     "git status --short"
   ],
-  "next_recommended_action": "Fix graph import correctness: CS-013, then add 
round-trip contract tests."
+  "next_recommended_action": "Fix global config mutation and provider 
validation: CS-011 and CS-012."
 }
diff --git a/.workflow/code-scan/reports/final-code-scan-report.md 
b/.workflow/code-scan/reports/final-code-scan-report.md
index e51218fb..d6dc2eed 100644
--- a/.workflow/code-scan/reports/final-code-scan-report.md
+++ b/.workflow/code-scan/reports/final-code-scan-report.md
@@ -78,7 +78,7 @@ None.
 
 1. Fix `CS-001` immediately: lock down `/logs` path handling and default admin 
credentials. Status: fixed after the scan.
 2. Fix the client error-contract cluster: `CS-002`, `CS-004`, `CS-008`. 
Status: fixed after the scan.
-3. Fix graph import correctness: `CS-013`, then add the missing round-trip 
tests.
+3. Fix graph import correctness: `CS-013`, then add the missing round-trip 
tests. Status: fixed after the scan.
 4. Fix global config mutation and provider validation: `CS-011`, `CS-012`.
 5. Replace fake integration tests with production-flow smoke coverage before 
broader refactors.
 
@@ -88,3 +88,4 @@ None.
 - `CS-002`: fixed by redacting sensitive request fields before client 
debug/error logs are emitted.
 - `CS-004`: fixed by raising `ResponseParseError` for malformed successful 
responses.
 - `CS-008`: fixed by preserving lower-level exceptions from Gremlin execution 
instead of wrapping every failure as `NotFoundError`.
+- `CS-013`: fixed by preserving extracted property value types through the 
full extraction-to-commit path.
diff --git a/.workflow/code-scan/reports/issues.md 
b/.workflow/code-scan/reports/issues.md
index 04fed7fe..67e56604 100644
--- a/.workflow/code-scan/reports/issues.md
+++ b/.workflow/code-scan/reports/issues.md
@@ -57,7 +57,7 @@ Issue IDs use `CS-NNN`. Priorities are P0 highest through P5 
lowest.
 - Module: `hugegraph-python-client`
 - Layer: transport / response validation
 - Paths: `hugegraph-python-client/src/pyhugegraph/utils/util.py:85`, 
`hugegraph-python-client/src/pyhugegraph/utils/util.py:136`
-- Status: open
+- Status: fixed
 - Evidence: `ResponseValidation.__call__()` catches broad `Exception` after 
successful HTTP parsing and returns the default `{}`. A `200 OK` response with 
malformed JSON becomes an empty dict.
 - Impact: Protocol drift or corrupt responses are indistinguishable from 
legitimate empty results.
 - Fix: successful-response parse failures now raise `ResponseParseError` 
instead of returning `{}`.
@@ -168,8 +168,8 @@ Issue IDs use `CS-NNN`. Priorities are P0 highest through 
P5 lowest.
 - Status: open
 - Evidence: `filter_item()` converts non-string properties to strings, while 
`Commit2Graph` enforces schema Python types and skips mismatches. Edge writes 
can continue and the flow reports success.
 - Impact: KG import can partially fail while the UI reports success.
-- Recommendation: Preserve schema-typed values or add a schema-aware 
normalization layer; aggregate and surface import failures.
-- Test note: Added `FIXME:` comments in property graph and commit tests.
+- Fix: `filter_item()` no longer stringifies non-string property values, so 
extracted JSON numeric values survive into `Commit2Graph` schema validation.
+- Test note: Added extraction-to-commit round-trip coverage proving 
`PropertyGraphExtract.run()` preserves typed values accepted by `Commit2Graph`.
 
 ### CS-014: Graph/vector dependency failures are treated as empty retrieval
 
diff --git a/.workflow/code-scan/reports/test-quality-ledger.md 
b/.workflow/code-scan/reports/test-quality-ledger.md
index c9db6eb0..a909f039 100644
--- a/.workflow/code-scan/reports/test-quality-ledger.md
+++ b/.workflow/code-scan/reports/test-quality-ledger.md
@@ -11,7 +11,6 @@ Added specific `FIXME:` comments in these files:
 - `hugegraph-llm/src/tests/indices/test_faiss_vector_index.py`
 - `hugegraph-llm/src/tests/operators/hugegraph_op/test_commit_to_hugegraph.py`
 - 
`hugegraph-llm/src/tests/operators/hugegraph_op/test_commit_to_hugegraph_load_into_graph.py`
-- `hugegraph-llm/src/tests/operators/llm_op/test_property_graph_extract.py`
 - `hugegraph-llm/src/tests/integration/test_graph_rag_pipeline.py`
 - `hugegraph-llm/src/tests/integration/test_rag_pipeline.py`
 - `hugegraph-llm/src/tests/integration/test_kg_construction.py`
@@ -40,7 +39,6 @@ Added specific `FIXME:` comments in these files:
 - `PropertyKey` advanced builder payload.
 - `IndexLabel` multi-field order.
 - `Commit2Graph.load_into_graph()` partial-failure behavior.
-- `PropertyGraphExtract -> Commit2Graph` typed round trip.
 - `GraphQueryNode` and `VectorQueryNode` dependency failure propagation.
 - `VectorQueryNode` top-k and threshold parameter pass-through.
 - `LiteLLMEmbedding` factory construction.
@@ -59,3 +57,4 @@ Added specific `FIXME:` comments in these files:
 - `CS-002`: client transport and response-validation tests now prove 
password-like request fields are redacted from debug/error logs.
 - `CS-004`: response-validation tests now prove malformed successful JSON 
raises `ResponseParseError`.
 - `CS-008`: Gremlin tests now prove lower-level auth exceptions keep their 
original type through `GremlinManager.exec()`.
+- `CS-013`: extraction-to-commit round-trip tests now prove schema-typed 
numeric values survive `PropertyGraphExtract.run()` and are accepted by 
`Commit2Graph`.
diff --git 
a/hugegraph-llm/src/hugegraph_llm/operators/llm_op/property_graph_extract.py 
b/hugegraph-llm/src/hugegraph_llm/operators/llm_op/property_graph_extract.py
index ec4f7f33..dbe6f907 100644
--- a/hugegraph-llm/src/hugegraph_llm/operators/llm_op/property_graph_extract.py
+++ b/hugegraph-llm/src/hugegraph_llm/operators/llm_op/property_graph_extract.py
@@ -73,9 +73,6 @@ def filter_item(schema, items) -> List[Dict[str, Any]]:
             for key in non_nullable_keys:
                 if key not in item["properties"]:
                     item["properties"][key] = "NULL"
-        for key, value in item["properties"].items():
-            if not isinstance(value, str):
-                item["properties"][key] = str(value)
         filtered_items.append(item)
 
     return filtered_items
diff --git 
a/hugegraph-llm/src/tests/operators/hugegraph_op/test_commit_to_hugegraph_load_into_graph.py
 
b/hugegraph-llm/src/tests/operators/hugegraph_op/test_commit_to_hugegraph_load_into_graph.py
index e9b6d803..d576f902 100644
--- 
a/hugegraph-llm/src/tests/operators/hugegraph_op/test_commit_to_hugegraph_load_into_graph.py
+++ 
b/hugegraph-llm/src/tests/operators/hugegraph_op/test_commit_to_hugegraph_load_into_graph.py
@@ -26,8 +26,8 @@ from hugegraph_llm.operators.llm_op.property_graph_extract 
import PropertyGraphE
 
 pytestmark = [pytest.mark.unit]
 
-# FIXME: cover the extract -> commit round trip and assert that vertex type
-# failures stop edge writes and surface an explicit import failure.
+# FIXME: cover failure branches where vertex type errors stop edge writes and
+# surface an explicit import failure.
 
 
 class TestCommit2GraphLoadIntoGraph(unittest.TestCase):
@@ -326,6 +326,67 @@ class TestCommit2GraphLoadIntoGraph(unittest.TestCase):
             {"role": "Forrest Gump"},
         )
 
+    
@patch("hugegraph_llm.operators.hugegraph_op.commit_to_hugegraph.Commit2Graph._handle_graph_creation")
+    def 
test_property_graph_extract_run_preserves_typed_values_for_commit(self, 
mock_handle_graph_creation):
+        """Test extracted typed properties survive the full 
extraction-to-commit path."""
+        mock_handle_graph_creation.side_effect = [
+            MagicMock(id="1:Tom Hanks"),
+            MagicMock(id="2:Forrest Gump"),
+            MagicMock(id="edge_id"),
+        ]
+        llm = MagicMock()
+        llm.generate.return_value = """{
+            "vertices": [
+            {
+                "label": "person",
+                "properties": {
+                    "name": "Tom Hanks",
+                    "age": 67
+                }
+            },
+            {
+                "label": "movie",
+                "properties": {
+                    "title": "Forrest Gump",
+                    "year": 1994
+                }
+            }
+            ],
+            "edges": [
+            {
+                "label": "acted_in",
+                "properties": {
+                    "role": "Forrest Gump"
+                },
+                "source": {
+                    "label": "person",
+                    "properties": {
+                        "name": "Tom Hanks"
+                    }
+                },
+                "target": {
+                    "label": "movie",
+                    "properties": {
+                        "title": "Forrest Gump"
+                    }
+                }
+            }
+            ]
+        }"""
+        context = PropertyGraphExtract(llm=llm, example_prompt=None).run(
+            {
+                "schema": self.schema,
+                "chunks": ["Tom Hanks acted in Forrest Gump."],
+            }
+        )
+
+        self.assertIsInstance(context["vertices"][0]["properties"]["age"], int)
+        self.assertIsInstance(context["vertices"][1]["properties"]["year"], 
int)
+
+        self.commit2graph.load_into_graph(context["vertices"], 
context["edges"], self.schema)
+
+        self.assertEqual(mock_handle_graph_creation.call_count, 3)
+
     
@patch("hugegraph_llm.operators.hugegraph_op.commit_to_hugegraph.Commit2Graph._handle_graph_creation")
     def 
test_load_into_graph_raises_explicit_error_when_vertex_creation_fails(self, 
mock_handle_graph_creation):
         """Test failed vertex creation is reported before edge creation."""
diff --git 
a/hugegraph-llm/src/tests/operators/llm_op/test_property_graph_extract.py 
b/hugegraph-llm/src/tests/operators/llm_op/test_property_graph_extract.py
index df27c868..dba5abfa 100644
--- a/hugegraph-llm/src/tests/operators/llm_op/test_property_graph_extract.py
+++ b/hugegraph-llm/src/tests/operators/llm_op/test_property_graph_extract.py
@@ -34,9 +34,6 @@ from hugegraph_llm.operators.llm_op.property_graph_extract 
import (
 
 pytestmark = pytest.mark.contract
 
-# FIXME: add a property-graph extraction to Commit2Graph contract test that
-# preserves schema-typed values instead of stringifying numeric/date fields.
-
 
 class TestPropertyGraphExtract(unittest.TestCase):
     def setUp(self):
@@ -191,8 +188,8 @@ class TestPropertyGraphExtract(unittest.TestCase):
         # Check that title (non-nullable) was added with NULL value
         self.assertEqual(filtered_items[1]["properties"]["title"], "NULL")
 
-        # Check that year was converted to string
-        self.assertEqual(filtered_items[1]["properties"]["year"], "1994")
+        # Check that schema-typed values are preserved for Commit2Graph
+        self.assertEqual(filtered_items[1]["properties"]["year"], 1994)
 
     def test_extract_property_graph_by_llm(self):
         """Test the extract_property_graph_by_llm method."""

Reply via email to