Commit 169d1bae20458cb1cd0f538c8ec0ae15a4f5c8d2

Authored by graphlemon
1 parent 01987427

graphlemon: auto-commit uncommitted changes for 46748e02-6e65-49f5-a3ae-2f2bdea9…

…3d96-main-checkout-drift
src/test_work_graph_orchestrate.py
@@ -547,6 +547,27 @@ class RunFnLogsExecutionEventsTest(RunGraphTestBase): @@ -547,6 +547,27 @@ class RunFnLogsExecutionEventsTest(RunGraphTestBase):
547 self.assertEqual([e["event"] for e in events], ["node_start", "node_completed"]) 547 self.assertEqual([e["event"] for e in events], ["node_start", "node_completed"])
548 self.assertEqual(events[1]["output"], {"content": "brd text"}) 548 self.assertEqual(events[1]["output"], {"content": "brd text"})
549 549
  550 + def test_non_ascii_content_written_as_real_utf8_not_escaped(self):
  551 + # User-reported (2026-08-13): v_log_viewer reads this .jsonl file's
  552 + # raw bytes back and displays each line AS-IS (never JSON.parse()s
  553 + # it), unlike every other json.dumps() call in this codebase whose
  554 + # output always gets re-parsed before display. Without
  555 + # ensure_ascii=False, real Chinese content here showed up in the
  556 + # console as literal \uXXXX escape sequences instead of the actual
  557 + # characters.
  558 + manifest = {"nodes": [{"node_id": "brd", "depends_on": []}], "edges": []}
  559 + with patch.object(
  560 + org_node_trigger, "trigger_org_node_structured", return_value={"content": "期望行为:真实中文内容"}
  561 + ):
  562 + wgo.run_graph(
  563 + self.conn, "run-1", "planner", "planner-doc-writing", "/tmp/proj-1", manifest,
  564 + lambda node, outputs: "p", _IN_SCHEMA, _OUT_SCHEMA,
  565 + )
  566 +
  567 + raw_content = execution_log.get_log(self.conn, self._node_exec_id())["content"]
  568 + self.assertIn("期望行为:真实中文内容", raw_content)
  569 + self.assertNotIn("\\u671f", raw_content) # 期 == 期, the escaped form this bug produced
  570 +
550 # also exercise the real HTTP-facing read path end to end (not just 571 # also exercise the real HTTP-facing read path end to end (not just
551 # the module function) -- an empty file was exactly bug A1. 572 # the module function) -- an empty file was exactly bug A1.
552 row = self.conn.execute( 573 row = self.conn.execute(
src/work_graph_orchestrate.py
@@ -99,8 +99,17 @@ from src import ( @@ -99,8 +99,17 @@ from src import (
99 99
100 100
101 def _log_event(conn, node_exec_id, event_type, **payload): 101 def _log_event(conn, node_exec_id, event_type, **payload):
  102 + # ensure_ascii=False (2026-08-13, user-reported): this is the ONLY
  103 + # json.dumps() call in the codebase whose output is displayed as raw
  104 + # TEXT (v_log_viewer reads the .jsonl file's bytes back and shows each
  105 + # line as-is, never JSON.parse()s it back into structured data) --
  106 + # every other json.dumps() call here stores data that's always
  107 + # JSON.parse()d/json.loads()d again before display, so the default
  108 + # \uXXXX escaping round-trips invisibly there. Here it doesn't: real
  109 + # Chinese (or any non-ASCII) content in `payload` showed up as literal
  110 + # \uXXXX escape sequences in the console instead of the actual text.
102 execution_log.append_log( 111 execution_log.append_log(
103 - conn, node_exec_id, json.dumps({"event": event_type, **payload}) + "\n" 112 + conn, node_exec_id, json.dumps({"event": event_type, **payload}, ensure_ascii=False) + "\n"
104 ) 113 )
105 114
106 115