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

zclllyybb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new d445bf1071b [improvement](ci) Strengthen Codex review context and 
Litefuse observability (#65178)
d445bf1071b is described below

commit d445bf1071b9e3c9472085a0160fd3bcacd7292a
Author: zclllyybb <[email protected]>
AuthorDate: Sun Jul 12 15:20:40 2026 +0800

    [improvement](ci) Strengthen Codex review context and Litefuse 
observability (#65178)
    
    The Codex GitHub Actions review pipeline needed stronger guarantees that
    agents review the intended PR snapshot, use one authoritative diff,
    pursue high-risk cross-module mechanisms, and expose the work of spawned
    subagents in Litefuse.
    
    This PR:
    
    - verifies the checked-out PR head and rechecks the live base/head after
    context preparation;
    - prepares an authoritative aggregate PR patch and changed-file list,
    with atomic bounded retry (`2s`, `4s`, `8s`) for transient GitHub API
    failures;
    - directs the main agent to perform an initial risk scan, dispatch
    focused subagents for suspicious mechanisms, maintain a shared
    append-only ledger, validate/deduplicate every candidate, and converge
    for at most three rounds;
    - requires paths outside the authoritative diff/changed-file context to
    be confirmed with `rg --files` before reading;
    - records separate Litefuse traces for each Codex subagent session,
    including command/tool I/O and non-empty encrypted-reasoning status,
    instead of mixing subagent activity into the main trace;
    - makes Litefuse ingestion more resilient to transport timeouts while
    keeping telemetry upload non-blocking for the review outcome.
    
    The repository review skill is kept focused on review invariants;
    orchestration and completion policy live in the workflow prompt, where
    they are available to the GitHub Actions invocation.
    
    ### Validation and experiment material
    
    - Static checks: `python3 -m py_compile
    .github/scripts/emit_litefuse_otel_io.py` and `git diff --check`.
    - Litefuse uploader validation: real/synthetic subagent session
    conversion, payload-limit coverage, and readback of independent subagent
    traces.
    - End-to-end replayed review experiments against fresh fork PRs built
    from the original PR base/head commits:
    
    | Replay PR | GitHub Actions run | Result |
    | --- | --- | --- |
    | [#136](https://github.com/zclllyybb/doris/pull/136) |
    [29112823062](https://github.com/zclllyybb/doris/actions/runs/29112823062)
    | Success; 2 inline comments |
    | [#137](https://github.com/zclllyybb/doris/pull/137) |
    [29114260631](https://github.com/zclllyybb/doris/actions/runs/29114260631)
    | Success; 3 inline comments |
    | [#138](https://github.com/zclllyybb/doris/pull/138) |
    [29115946034](https://github.com/zclllyybb/doris/actions/runs/29115946034)
    | Success; 1 inline comment |
    | [#139](https://github.com/zclllyybb/doris/pull/139) |
    [29150372758](https://github.com/zclllyybb/doris/actions/runs/29150372758)
    | Success; 1 inline comment |
    | [#140](https://github.com/zclllyybb/doris/pull/140) |
    [29151057520](https://github.com/zclllyybb/doris/actions/runs/29151057520)
    | Success; 1 inline comment |
    
    The latest replay trace, `86be226391a40e5992bb8d3b4e125eca`, confirms
    one authoritative `pr.diff` read, two changed-file-list reads, no `gh pr
    diff` or `git diff` calls from the reviewing agent, and separate
    subagent sessions. It also exposed one remaining prompt-compliance gap:
    a guessed adjacent `.cpp` path was read without a preceding `rg --files`
    lookup; this is documented test evidence rather than hidden by the
    validation.
---
 .claude/skills/code-review/SKILL.md      |  13 +-
 .github/scripts/emit_litefuse_otel_io.py | 619 ++++++++++++++++++++++++++++++-
 .github/workflows/code-review-runner.yml | 155 +++++---
 be/src/core/AGENTS.md                    |  18 +
 be/src/format/table/jdbc_jni_reader.cpp  |   2 +-
 5 files changed, 738 insertions(+), 69 deletions(-)

diff --git a/.claude/skills/code-review/SKILL.md 
b/.claude/skills/code-review/SKILL.md
index dea95615b8a..c164d60a569 100644
--- a/.claude/skills/code-review/SKILL.md
+++ b/.claude/skills/code-review/SKILL.md
@@ -14,13 +14,9 @@ Use this when you need to review code, whether it is code 
you just completed or
 
 ## How to use me
 
-0. **MANDATORY GOAL COMPLETION REQUIREMENT:** When the review is running in 
Codex goal mode, the goal is complete only after every changed file and 
relevant surrounding code path has been examined, every suspicious point has 
been accepted as an inline issue or dismissed with evidence, and every accepted 
issue has been submitted and verified on GitHub.
-1. **MANDATORY GOAL PROCESS REQUIREMENT:** The goal's progress tracking must 
cover instruction loading, subagent spawning, shared-ledger maintenance, 
candidate verification/deduplication, final subagent convergence, GitHub review 
submission, and GitHub API verification. The goal is not complete until every 
live subagent has said `NO_NEW_VALUABLE_FINDINGS` for the same current 
ledger/comment set after the last candidate update.
-2. **MANDATORY SUBAGENT REVIEW REQUIREMENT:** Use the available subagent or 
multi-agent spawn tool for focused review passes; do not merely simulate 
subagent output. The main agent must read the subagent results, independently 
verify or dismiss every candidate with concrete code evidence, deduplicate 
against existing review threads, submit the final GitHub review itself, and 
summarize the subagent conclusions.
-3. **MANDATORY SHARED LEDGER REQUIREMENT:** When a shared subagent review 
ledger is provided, every subagent must read the whole ledger and append 
findings only to its assigned subagent section. The main agent must use the 
ledger as the source of truth for merging, status updates, duplicate 
suppression, proposed final comments, and the final convergence round. 
Subagents must not edit another subagent section or any main-owned section; 
this section-owned append-only rule avoids concurrent [...]
-4. **Always read and respond to Part 1** (General Principles) — it applies to 
all code.
-5. For module-specific review, **read the `AGENTS.md` in the corresponding 
source directory** listed in Part 2. Those files contain non-obvious 
conventions and traps specific to each subsystem.
-6. Parts 3–7 cover cross-module concerns, testing, high-risk patterns, 
functions, and standards — refer as needed.
+1. **Always read and respond to Part 1** (General Principles) — it applies to 
all code.
+2. For module-specific review, **read the `AGENTS.md` in the corresponding 
source directory** listed in Part 2. Those files contain non-obvious 
conventions and traps specific to each subsystem.
+3. Parts 3–7 cover cross-module concerns, testing, high-risk patterns, 
functions, and standards — refer as needed.
 
 ---
 
@@ -29,6 +25,7 @@ Use this when you need to review code, whether it is code you 
just completed or
 ### 1.1 Core Invariants
 
 Always focus on the following core invariants during review:
+
 1. **Data Correctness**: Data from any committed transaction must be visible 
to subsequent queries and not lost; data from uncommitted transactions must not 
be visible
 2. **Version Consistency**: Partition visible version is the sole standard for 
data visibility; BE must strictly read data not exceeding this version
 3. **Delete Bitmap Consistency** (MoW tables): delete bitmap must be strictly 
aligned with rowset versions; sentinel marks and `TEMP_VERSION`-style 
placeholders must be replaced with actual versions before use
@@ -138,7 +135,7 @@ If it involves the judgment of concurrent scenarios, it is 
necessary to find the
 
 - [ ] **Reservation**: `try_reserve()` before large allocations, with 
guaranteed release on every exit path
 - [ ] **Allocator-aware ownership**: In BE code, for memory-owning containers 
or buffers that should be tracked by Doris memory accounting, prefer 
allocator-aware types from `be/src/core/custom_allocator.h` such as 
`DorisVector`, `DorisMap`, and `DorisUniqueBufferPtr` instead of `std::vector`, 
`std::map`, and `std::unique_ptr`
-- [ ] **Ownership**: See `be/src/runtime/AGENTS.md` for cache-handle, 
shared_ptr-cycle, and factory-creator rules
+- [ ] **Ownership**: See `be/src/runtime/AGENTS.md` for cache-handle, 
shared_ptr-cycle, and factory-creator rules. See `be/src/core/AGENTS.md` for 
Proper application of the cow mechanism related to `IColumn`, `Block`...
 
 #### 1.3.4 Data Correctness (High Priority)
 
diff --git a/.github/scripts/emit_litefuse_otel_io.py 
b/.github/scripts/emit_litefuse_otel_io.py
index 351b5b5cbf3..d11e465df87 100644
--- a/.github/scripts/emit_litefuse_otel_io.py
+++ b/.github/scripts/emit_litefuse_otel_io.py
@@ -488,6 +488,513 @@ def build_ingestion_payload(args, input_text, 
output_text, events):
     return trace_id, {"batch": batch}, len(batch) - 1
 
 
+def main_trace_metadata(args):
+    trace_metadata = {
+        "repository": args.repository,
+        "workflow": args.workflow,
+        "run_id": args.run_id,
+        "pr_number": args.pr_number,
+        "head_sha": args.head_sha,
+        "base_sha": args.base_sha,
+        "model_reasoning_effort": args.reasoning_effort,
+    }
+    return {
+        key: value for key, value in trace_metadata.items() if value not in 
(None, "")
+    }
+
+
+def receiver_thread_ids(events):
+    thread_ids = set()
+    for event in events:
+        item = event.get("item") if isinstance(event.get("item"), dict) else {}
+        if item.get("type") != "collab_tool_call":
+            continue
+        for thread_id in item.get("receiver_thread_ids") or []:
+            if thread_id:
+                thread_ids.add(str(thread_id))
+    return thread_ids
+
+
+def session_jsonl_files(root):
+    if not root or not os.path.isdir(root):
+        return []
+    paths = []
+    for dirpath, _dirnames, filenames in os.walk(root):
+        for filename in filenames:
+            if filename.endswith(".jsonl"):
+                paths.append(os.path.join(dirpath, filename))
+    return sorted(paths)
+
+
+def session_meta(events):
+    for event in events:
+        if event.get("type") != "session_meta":
+            continue
+        payload = event.get("payload")
+        if isinstance(payload, dict):
+            return payload
+    return {}
+
+
+def subagent_spawn(meta):
+    source = meta.get("source") if isinstance(meta, dict) else {}
+    source = source if isinstance(source, dict) else {}
+    subagent = source.get("subagent")
+    subagent = subagent if isinstance(subagent, dict) else {}
+    spawn = subagent.get("thread_spawn")
+    return spawn if isinstance(spawn, dict) else {}
+
+
+def is_subagent_meta(meta, expected_thread_ids):
+    if not isinstance(meta, dict):
+        return False
+    thread_id = str(meta.get("id") or "")
+    if expected_thread_ids:
+        return thread_id in expected_thread_ids
+    if meta.get("thread_source") == "subagent":
+        return True
+    source = meta.get("source")
+    return isinstance(source, dict) and bool(source.get("subagent"))
+
+
+def compact_session_meta(meta, max_json_chars):
+    compact = {}
+    for key in (
+        "id",
+        "parent_thread_id",
+        "timestamp",
+        "cwd",
+        "originator",
+        "cli_version",
+        "thread_source",
+        "agent_nickname",
+        "agent_role",
+        "model_provider",
+        "model",
+    ):
+        if meta.get(key) not in (None, ""):
+            compact[key] = meta.get(key)
+    for key in ("base_instructions", "user_instructions"):
+        if key in meta:
+            compact[f"{key}_present"] = True
+    source = meta.get("source")
+    if isinstance(source, dict):
+        compact["source"] = truncate_json(source, max_json_chars)
+    return compact
+
+
+def session_content_text(content, max_chars):
+    if isinstance(content, str):
+        return truncate_text(content, max_chars)
+    if not isinstance(content, list):
+        return truncate_json(content, max_chars)
+    parts = []
+    for item in content:
+        if isinstance(item, str):
+            parts.append(item)
+            continue
+        if not isinstance(item, dict):
+            parts.append(json_attr(item))
+            continue
+        for key in ("text", "input_text", "output_text"):
+            if isinstance(item.get(key), str):
+                parts.append(item[key])
+                break
+        else:
+            parts.append(json_attr(item))
+    return truncate_text("\n".join(parts), max_chars)
+
+
+def session_first_user_message(events, max_chars):
+    for event in events:
+        if event.get("type") != "response_item":
+            continue
+        payload = event.get("payload") if isinstance(event.get("payload"), 
dict) else {}
+        if payload.get("type") == "message" and payload.get("role") == "user":
+            text = session_content_text(payload.get("content"), max_chars)
+            if isinstance(text, str) and text.strip():
+                return text
+    return ""
+
+
+def session_final_assistant_message(events, max_chars):
+    for event in reversed(events):
+        payload = event.get("payload") if isinstance(event.get("payload"), 
dict) else {}
+        if event.get("type") == "response_item":
+            if payload.get("type") == "message" and payload.get("role") == 
"assistant":
+                text = session_content_text(payload.get("content"), max_chars)
+                if isinstance(text, str) and text.strip():
+                    return text
+        elif event.get("type") == "event_msg" and payload.get("type") == 
"agent_message":
+            text = payload.get("message") or ""
+            if text.strip():
+                return truncate_text(text, max_chars)
+    return ""
+
+
+def safe_name_component(value):
+    text = str(value or "unknown")
+    safe = "".join(
+        char if char.isalnum() or char in "._-" else "_" for char in text
+    ).strip("._-")
+    return safe[:120] or "unknown"
+
+
+def jsonish(value):
+    if not isinstance(value, str):
+        return value
+    try:
+        return json.loads(value)
+    except json.JSONDecodeError:
+        return value
+
+
+def session_call_outputs(events):
+    outputs = {}
+    for event in events:
+        payload = event.get("payload") if isinstance(event.get("payload"), 
dict) else {}
+        if payload.get("type") != "function_call_output":
+            continue
+        call_id = payload.get("call_id")
+        if call_id and call_id not in outputs:
+            outputs[call_id] = (payload, event)
+    return outputs
+
+
+def session_event_timestamp(event, fallback_ns):
+    timestamp = event.get("timestamp")
+    if isinstance(timestamp, str) and timestamp:
+        return timestamp
+    return iso_from_ns(fallback_ns)
+
+
+def ns_from_iso(timestamp):
+    if not isinstance(timestamp, str) or not timestamp:
+        return None
+    try:
+        normalized = timestamp.replace("Z", "+00:00")
+        return int(datetime.fromisoformat(normalized).timestamp() * 
1_000_000_000)
+    except ValueError:
+        return None
+
+
+def session_observation_shape(event, call_outputs, max_json_chars):
+    event_type = event.get("type") or "unknown"
+    payload = event.get("payload") if isinstance(event.get("payload"), dict) 
else {}
+
+    if event_type == "session_meta":
+        compact_meta = compact_session_meta(payload, max_json_chars)
+        return {
+            "name": "codex.subagent.session_meta",
+            "type": "span",
+            "input": compact_meta,
+            "output": {
+                "thread_source": compact_meta.get("thread_source"),
+                "status": "recorded",
+            },
+            "metadata": {"session_event_type": event_type},
+        }
+
+    if event_type == "turn_context":
+        return {
+            "name": "codex.subagent.turn_context",
+            "type": "span",
+            "input": truncate_json(payload, max_json_chars),
+            "output": {"status": "recorded"},
+            "metadata": {"session_event_type": event_type},
+        }
+
+    if event_type == "event_msg":
+        message_type = payload.get("type") or "unknown"
+        message = payload.get("message") or ""
+        body = {
+            key: value
+            for key, value in payload.items()
+            if key not in ("message", "text_elements", "images", 
"local_images")
+        }
+        if payload.get("text_elements"):
+            body["text_elements"] = truncate_json(
+                payload.get("text_elements"), max_json_chars
+            )
+        if payload.get("images"):
+            body["images"] = truncate_json(payload.get("images"), 
max_json_chars)
+        return {
+            "name": 
f"codex.subagent.event.{safe_name_component(message_type)}",
+            "type": "generation" if message_type == "agent_message" else 
"span",
+            "input": {
+                "session_event_type": event_type,
+                "message_type": message_type,
+                "payload": truncate_json(body, max_json_chars),
+            },
+            "output": {
+                "message": truncate_text(message, max_json_chars),
+                "status": "recorded",
+            },
+            "metadata": {
+                "session_event_type": event_type,
+                "message_type": message_type,
+            },
+        }
+
+    if event_type != "response_item":
+        return {
+            "name": f"codex.subagent.{safe_name_component(event_type)}",
+            "type": "span",
+            "input": {"session_event_type": event_type},
+            "output": truncate_json(payload, max_json_chars),
+            "metadata": {"session_event_type": event_type},
+        }
+
+    item_type = payload.get("type") or "unknown"
+    if item_type == "message":
+        role = payload.get("role") or "unknown"
+        text = session_content_text(payload.get("content"), max_json_chars)
+        is_assistant = role == "assistant"
+        return {
+            "name": f"codex.subagent.message.{safe_name_component(role)}",
+            "type": "generation" if is_assistant else "span",
+            "input": {
+                "session_event_type": event_type,
+                "item_type": item_type,
+                "role": role,
+                "phase": payload.get("phase"),
+                **({} if is_assistant else {"content": text}),
+            },
+            "output": (
+                {"text": text}
+                if is_assistant
+                else {"status": "recorded", "role": role}
+            ),
+            "metadata": {
+                "session_event_type": event_type,
+                "item_type": item_type,
+                "role": role,
+                "phase": payload.get("phase"),
+            },
+        }
+
+    if item_type == "function_call":
+        call_id = payload.get("call_id")
+        output_payload, output_event = call_outputs.get(call_id, ({}, {}))
+        return {
+            "name": 
f"codex.subagent.tool.{safe_name_component(payload.get('name'))}",
+            "type": "span",
+            "input": {
+                "name": payload.get("name"),
+                "call_id": call_id,
+                "arguments": truncate_json(
+                    jsonish(payload.get("arguments")), max_json_chars
+                ),
+            },
+            "output": {
+                "call_id": call_id,
+                "output": truncate_json(
+                    jsonish(output_payload.get("output")), max_json_chars
+                ),
+                "status": "completed" if output_payload else "unknown",
+            },
+            "metadata": {
+                "session_event_type": event_type,
+                "item_type": item_type,
+                "tool_name": payload.get("name"),
+                "call_id": call_id,
+                "output_line": output_event.get("_line_number"),
+            },
+        }
+
+    if item_type == "function_call_output":
+        return {
+            "name": "codex.subagent.tool_output",
+            "type": "span",
+            "input": {"call_id": payload.get("call_id")},
+            "output": truncate_json(jsonish(payload.get("output")), 
max_json_chars),
+            "metadata": {
+                "session_event_type": event_type,
+                "item_type": item_type,
+                "call_id": payload.get("call_id"),
+            },
+        }
+
+    if item_type == "reasoning":
+        encrypted_content_present = bool(payload.get("encrypted_content"))
+        return {
+            "name": "codex.subagent.reasoning",
+            "type": "span",
+            "input": {
+                "session_event_type": event_type,
+                "item_type": item_type,
+                "encrypted_content_present": encrypted_content_present,
+            },
+            "output": {
+                "summary": truncate_json(payload.get("summary"), 
max_json_chars),
+                "encrypted_content_present": encrypted_content_present,
+                "status": "recorded",
+            },
+            "metadata": {"session_event_type": event_type, "item_type": 
item_type},
+        }
+
+    return {
+        "name": 
f"codex.subagent.response_item.{safe_name_component(item_type)}",
+        "type": "span",
+        "input": {"session_event_type": event_type, "item_type": item_type},
+        "output": truncate_json(payload, max_json_chars),
+        "metadata": {"session_event_type": event_type, "item_type": item_type},
+    }
+
+
+def build_subagent_session_payload(args, session_path, session_events):
+    now = time.time_ns()
+    meta = session_meta(session_events)
+    spawn = subagent_spawn(meta)
+    thread_id = str(meta.get("id") or os.path.basename(session_path))
+    parent_thread_id = (
+        spawn.get("parent_thread_id") or meta.get("parent_thread_id") or ""
+    )
+    agent_nickname = meta.get("agent_nickname") or spawn.get("agent_nickname") 
or ""
+    agent_role = meta.get("agent_role") or spawn.get("agent_role") or ""
+    trace_id = secrets.token_hex(16)
+    root_observation_id = secrets.token_hex(16)
+    trace_input = session_first_user_message(session_events, 
args.max_input_chars)
+    if not trace_input:
+        trace_input = json_attr(compact_session_meta(meta, 
args.max_json_chars))
+    trace_output = session_final_assistant_message(session_events, 
args.max_output_chars)
+    if not trace_output:
+        trace_output = json_attr({"session_status": "recorded"})
+
+    trace_metadata = {
+        **main_trace_metadata(args),
+        "codex_session_jsonl": True,
+        "subagent_session": True,
+        "main_session_id": args.session_id,
+        "thread_id": thread_id,
+        "parent_thread_id": parent_thread_id,
+        "agent_nickname": agent_nickname,
+        "agent_role": agent_role,
+        "session_file": session_path,
+        "session_event_count": len(session_events),
+    }
+    trace_metadata = {
+        key: value for key, value in trace_metadata.items() if value not in 
(None, "")
+    }
+    trace_session_id = f"{args.session_id}:subagent:{thread_id}"
+    first_timestamp = (
+        session_event_timestamp(session_events[0], now)
+        if session_events
+        else iso_from_ns(now)
+    )
+    base_ns = ns_from_iso(first_timestamp) or now
+    event_start_nses = [
+        ns_from_iso(event.get("timestamp")) or base_ns + offset * 1_000_000
+        for offset, event in enumerate(session_events, start=2)
+    ]
+    latest_event_start_ns = max(event_start_nses) if event_start_nses else 
base_ns
+    root_end = iso_from_ns(latest_event_start_ns + 1_000_000)
+    call_outputs = session_call_outputs(session_events)
+    function_call_ids = {
+        (event.get("payload") or {}).get("call_id")
+        for event in session_events
+        if event.get("type") == "response_item"
+        and isinstance(event.get("payload"), dict)
+        and event["payload"].get("type") == "function_call"
+        and event["payload"].get("call_id")
+    }
+
+    batch = [
+        ingestion_event(
+            "trace-create",
+            first_timestamp,
+            {
+                "id": trace_id,
+                "timestamp": first_timestamp,
+                "name": args.subagent_trace_name,
+                "input": trace_input,
+                "output": trace_output,
+                "sessionId": trace_session_id,
+                "environment": args.environment,
+                "metadata": trace_metadata,
+                "tags": ["doris-ai-review-subagent", "codex-session-jsonl"],
+            },
+        ),
+        ingestion_event(
+            "span-create",
+            first_timestamp,
+            {
+                "id": root_observation_id,
+                "traceId": trace_id,
+                "name": "codex.subagent.review",
+                "startTime": first_timestamp,
+                "endTime": root_end,
+                "input": {"session_file": session_path, "thread_id": 
thread_id},
+                "output": {"final_message": trace_output},
+                "environment": args.environment,
+                "metadata": trace_metadata,
+            },
+        ),
+    ]
+
+    observation_count = 1
+    for offset, event in enumerate(session_events, start=2):
+        payload = event.get("payload") if isinstance(event.get("payload"), 
dict) else {}
+        if (
+            event.get("type") == "response_item"
+            and payload.get("type") == "function_call_output"
+            and payload.get("call_id") in function_call_ids
+        ):
+            continue
+        shape = session_observation_shape(event, call_outputs, 
args.max_json_chars)
+        fallback_start_ns = base_ns + offset * 1_000_000
+        start_time = session_event_timestamp(event, fallback_start_ns)
+        end_ns = (ns_from_iso(start_time) or fallback_start_ns) + 750_000
+        body = {
+            "id": secrets.token_hex(16),
+            "traceId": trace_id,
+            "parentObservationId": root_observation_id,
+            "name": shape["name"],
+            "startTime": start_time,
+            "endTime": iso_from_ns(end_ns),
+            "input": shape["input"],
+            "output": shape["output"],
+            "environment": args.environment,
+            "metadata": {
+                **trace_metadata,
+                "session_event_type": event.get("type"),
+                "session_line": event.get("_line_number"),
+            },
+        }
+        for key, value in shape.get("metadata", {}).items():
+            if value not in (None, ""):
+                body["metadata"][key] = value
+        event_type = "generation-create" if shape["type"] == "generation" else 
"span-create"
+        if shape["type"] == "generation":
+            body["model"] = args.model
+        batch.append(ingestion_event(event_type, start_time, body))
+        observation_count += 1
+
+    return {
+        "trace_id": trace_id,
+        "session_id": trace_session_id,
+        "thread_id": thread_id,
+        "path": session_path,
+        "event_count": len(session_events),
+        "observation_count": observation_count,
+        "payload": {"batch": batch},
+    }
+
+
+def build_subagent_session_payloads(args, main_events):
+    expected_thread_ids = receiver_thread_ids(main_events)
+    payloads = []
+    for path in session_jsonl_files(args.subagent_sessions_dir):
+        events = load_jsonl(path)
+        meta = session_meta(events)
+        if not is_subagent_meta(meta, expected_thread_ids):
+            continue
+        payloads.append(build_subagent_session_payload(args, path, events))
+        if len(payloads) >= args.max_subagent_sessions:
+            break
+    return payloads
+
+
 def compact_json_bytes(payload):
     return json.dumps(payload, ensure_ascii=False, separators=(",", 
":")).encode("utf-8")
 
@@ -619,7 +1126,7 @@ def chunk_payload(payload, max_payload_bytes):
     return chunks
 
 
-def post_payload_once(endpoint, public_key, secret_key, payload):
+def post_payload_once(endpoint, public_key, secret_key, payload, 
timeout_seconds):
     auth = base64.b64encode(f"{public_key}:{secret_key}".encode()).decode()
     request = urllib.request.Request(
         endpoint,
@@ -630,7 +1137,7 @@ def post_payload_once(endpoint, public_key, secret_key, 
payload):
         },
         method="POST",
     )
-    with urllib.request.urlopen(request, timeout=30) as response:
+    with urllib.request.urlopen(request, timeout=timeout_seconds) as response:
         body = response.read().decode()
         detail = json.loads(body) if body else {}
         errors = detail.get("errors") if isinstance(detail, dict) else None
@@ -659,20 +1166,40 @@ def retry_payload_chunks_after_413(payload, 
request_size, max_payload_bytes):
     return chunk_payload(payload, next_limit)
 
 
-def post_payload(endpoint, public_key, secret_key, payload, max_payload_bytes):
+def retry_payload_chunks_after_transport_error(payload, request_size, 
max_payload_bytes):
+    batch = payload.get("batch") or []
+    if len(batch) <= 1:
+        return [(payload, request_size)]
+    next_limit = max(1_000, min(max_payload_bytes - 1, request_size // 2))
+    return chunk_payload(payload, next_limit)
+
+
+def post_payload(
+    endpoint,
+    public_key,
+    secret_key,
+    payload,
+    max_payload_bytes,
+    timeout_seconds,
+    retry_attempts,
+    retry_sleep_seconds,
+):
     statuses = []
     success_count = 0
     request_sizes = []
-    retry_count = 0
+    payload_too_large_retry_count = 0
+    transport_retry_count = 0
     chunks = chunk_payload(payload, max_payload_bytes)
     while chunks:
         chunk, request_size = chunks.pop(0)
         try:
-            status = post_payload_once(endpoint, public_key, secret_key, chunk)
+            status = post_payload_once(
+                endpoint, public_key, secret_key, chunk, timeout_seconds
+            )
         except urllib.error.HTTPError as exc:
             if exc.code != 413:
                 raise
-            retry_count += 1
+            payload_too_large_retry_count += 1
             chunks = (
                 retry_payload_chunks_after_413(
                     chunk, request_size, max_payload_bytes
@@ -680,6 +1207,21 @@ def post_payload(endpoint, public_key, secret_key, 
payload, max_payload_bytes):
                 + chunks
             )
             continue
+        except (TimeoutError, urllib.error.URLError) as exc:
+            transport_retry_count += 1
+            if transport_retry_count > retry_attempts:
+                raise RuntimeError(
+                    "Litefuse ingestion failed after transport retries: "
+                    f"{type(exc).__name__}: {exc}"
+                ) from exc
+            time.sleep(retry_sleep_seconds)
+            chunks = (
+                retry_payload_chunks_after_transport_error(
+                    chunk, request_size, max_payload_bytes
+                )
+                + chunks
+            )
+            continue
         statuses.append(status["status"])
         success_count += int(status.get("success_count") or 0)
         request_sizes.append(request_size)
@@ -688,7 +1230,8 @@ def post_payload(endpoint, public_key, secret_key, 
payload, max_payload_bytes):
         "request_count": len(statuses),
         "request_sizes": request_sizes,
         "max_request_size": max(request_sizes) if request_sizes else 0,
-        "payload_too_large_retries": retry_count,
+        "payload_too_large_retries": payload_too_large_retry_count,
+        "transport_retries": transport_retry_count,
         "success_count": success_count,
     }
 
@@ -961,6 +1504,8 @@ def parse_args():
     parser.add_argument("--events-file", required=True)
     parser.add_argument("--output-file", default="")
     parser.add_argument("--trace-name", default="doris-ai-review")
+    parser.add_argument("--subagent-trace-name", 
default="doris-ai-review-subagent")
+    parser.add_argument("--subagent-sessions-dir", default="")
     parser.add_argument("--session-id", required=True)
     parser.add_argument("--repository", default="")
     parser.add_argument("--workflow", default="")
@@ -976,6 +1521,10 @@ def parse_args():
     parser.add_argument("--max-json-chars", type=int, default=40_000)
     parser.add_argument("--max-context-json-chars", type=int, default=0)
     parser.add_argument("--max-payload-bytes", type=int, default=4_000_000)
+    parser.add_argument("--max-subagent-sessions", type=int, default=100)
+    parser.add_argument("--post-timeout-seconds", type=int, default=120)
+    parser.add_argument("--post-retry-attempts", type=int, default=5)
+    parser.add_argument("--post-retry-sleep-seconds", type=int, default=5)
     parser.add_argument("--verify", action="store_true")
     parser.add_argument("--dry-run", action="store_true")
     parser.add_argument("--verify-attempts", type=int, default=24)
@@ -1001,6 +1550,11 @@ def main():
     trace_id, payload, observation_count = build_ingestion_payload(
         args, input_text, output_text, events
     )
+    subagent_payloads = (
+        build_subagent_session_payloads(args, events)
+        if args.subagent_sessions_dir
+        else []
+    )
 
     result = {
         "dry_run": args.dry_run,
@@ -1009,6 +1563,7 @@ def main():
         "trace_id": trace_id,
         "session_id": args.session_id,
         "trace_name": args.trace_name,
+        "subagent_trace_count": len(subagent_payloads),
         "model": args.model,
         "reasoning_effort": args.reasoning_effort,
     }
@@ -1021,14 +1576,62 @@ def main():
         result["max_request_size"] = (
             max(result["request_sizes"]) if result["request_sizes"] else 0
         )
+        result["subagent_traces"] = []
+        for subagent_payload in subagent_payloads:
+            chunks = chunk_payload(subagent_payload["payload"], 
args.max_payload_bytes)
+            request_sizes = [request_size for _chunk, request_size in chunks]
+            result["subagent_traces"].append(
+                {
+                    "trace_id": subagent_payload["trace_id"],
+                    "session_id": subagent_payload["session_id"],
+                    "thread_id": subagent_payload["thread_id"],
+                    "path": subagent_payload["path"],
+                    "event_count": subagent_payload["event_count"],
+                    "observation_count": subagent_payload["observation_count"],
+                    "batch_count": len(subagent_payload["payload"]["batch"]),
+                    "request_count": len(chunks),
+                    "request_sizes": request_sizes,
+                    "max_request_size": max(request_sizes) if request_sizes 
else 0,
+                }
+            )
         print(json.dumps(result, sort_keys=True))
         return
 
     public_key = os.environ["LANGFUSE_PUBLIC_KEY"]
     secret_key = os.environ["LANGFUSE_SECRET_KEY"]
     result["status"] = post_payload(
-        endpoint, public_key, secret_key, payload, args.max_payload_bytes
+        endpoint,
+        public_key,
+        secret_key,
+        payload,
+        args.max_payload_bytes,
+        args.post_timeout_seconds,
+        args.post_retry_attempts,
+        args.post_retry_sleep_seconds,
     )
+    result["subagent_traces"] = []
+    for subagent_payload in subagent_payloads:
+        status = post_payload(
+            endpoint,
+            public_key,
+            secret_key,
+            subagent_payload["payload"],
+            args.max_payload_bytes,
+            args.post_timeout_seconds,
+            args.post_retry_attempts,
+            args.post_retry_sleep_seconds,
+        )
+        result["subagent_traces"].append(
+            {
+                "trace_id": subagent_payload["trace_id"],
+                "session_id": subagent_payload["session_id"],
+                "thread_id": subagent_payload["thread_id"],
+                "path": subagent_payload["path"],
+                "event_count": subagent_payload["event_count"],
+                "observation_count": subagent_payload["observation_count"],
+                "status": status,
+            }
+        )
 
     if args.verify:
         try:
diff --git a/.github/workflows/code-review-runner.yml 
b/.github/workflows/code-review-runner.yml
index 394f4173519..2eaa302d054 100644
--- a/.github/workflows/code-review-runner.yml
+++ b/.github/workflows/code-review-runner.yml
@@ -250,14 +250,59 @@ jobs:
             printf 'No additional user-provided review focus.\n' > 
"$REVIEW_CONTEXT_DIR/review_focus.txt"
           fi
 
-      - name: Prepare required AGENTS guides
+      - name: Prepare authoritative PR context and required AGENTS guides
         env:
           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           REPO: ${{ github.repository }}
           PR_NUMBER: ${{ inputs.pr_number }}
+          HEAD_SHA: ${{ inputs.head_sha }}
+          BASE_SHA: ${{ inputs.base_sha }}
           HELPER_REF: ${{ github.workflow_sha || github.sha }}
         run: |
-          gh api --paginate "repos/${REPO}/pulls/${PR_NUMBER}/files" --jq 
'.[].filename' > "$REVIEW_CONTEXT_DIR/pr_changed_files.txt"
+          checkout_head_sha="$(git rev-parse HEAD)"
+          if [ "$checkout_head_sha" != "$HEAD_SHA" ]; then
+            echo "Checked-out HEAD $checkout_head_sha does not match expected 
PR head $HEAD_SHA"
+            exit 1
+          fi
+
+          retry_to_file() {
+            local output_file="$1"
+            shift
+            local attempt delay=2 tmp_file
+            tmp_file="$(mktemp "${output_file}.tmp.XXXXXX")"
+
+            for attempt in 1 2 3 4; do
+              if "$@" > "$tmp_file"; then
+                mv "$tmp_file" "$output_file"
+                return 0
+              fi
+
+              if [ "$attempt" -lt 4 ]; then
+                echo "Attempt ${attempt}/4 failed while preparing 
${output_file}; retrying in ${delay}s..."
+                sleep "$delay"
+                delay=$((delay * 2))
+              fi
+            done
+
+            rm -f "$tmp_file"
+            return 1
+          }
+
+          retry_to_file "$REVIEW_CONTEXT_DIR/pr_changed_files.txt" \
+            gh api --paginate 
"repos/${REPO}/pulls/${PR_NUMBER}/files?per_page=100" \
+            --jq '.[].filename'
+          retry_to_file "$REVIEW_CONTEXT_DIR/pr.diff" \
+            gh pr diff "$PR_NUMBER" --repo "$REPO" --color=never
+
+          live_pr="$(gh api "repos/${REPO}/pulls/${PR_NUMBER}")"
+          live_head_sha="$(jq -r '.head.sha' <<<"$live_pr")"
+          live_base_sha="$(jq -r '.base.sha' <<<"$live_pr")"
+          if [ "$live_head_sha" != "$HEAD_SHA" ] || [ "$live_base_sha" != 
"$BASE_SHA" ]; then
+            echo "PR changed while review context was being prepared; restart 
the review"
+            echo "Expected base/head: $BASE_SHA $HEAD_SHA"
+            echo "Current base/head:  $live_base_sha $live_head_sha"
+            exit 1
+          fi
 
           helper="$RUNNER_TEMP/prepare_review_agents.py"
           gh api \
@@ -277,13 +322,13 @@ jobs:
       - name: Prepare review prompt
         run: |
           cat > "$REVIEW_CONTEXT_DIR/review_prompt.txt" <<'PROMPT'
-          This review task is executed in Codex goal mode. The review goal is 
complete only after every changed file and relevant surrounding code path has 
been examined, every suspicious point has a clear conclusion, and there is no 
remaining possibility of producing any new valuable review comment.
-
           You are performing an automated code review inside a GitHub Actions 
runner. The gh CLI is available and authenticated via GH_TOKEN.
           The current directory is the code repository for the PR to be 
reviewed.
+          This environment is only used for review operations, so do not 
attempt any builds or code modifications. However, temporary scripts you use 
for review purposes are exceptions.
           You MUST NOT attempt to access any files outside the current 
directory. and you DO NOT need to. But this does not prevent you from normally 
using any skill or web fetch tools.
           You can comment on the pull request.
-          Proceed with all subsequent research at the HIGHEST level of 
thought, aiming to identify all issues and submit all comments in JSON format.
+          This review task is executed in Codex goal mode. Subsequent prompts 
and skill indicate all the review and commenting actions you need to perform. 
The current round can only be concluded after completing the main agent risk 
scan, the normal full-review subagent review for each round, and the 
risk-focused subagent scan (if applicable). The final GitHub review can only be 
submitted after all subagents return NO_NEW_VALUABLE_FINDINGS, and all 
candidate points from the subagents hav [...]
+          In addition, the number of iterations shall not exceed 3 rounds. If 
new subagents identify valuable candidate points after 3 rounds, the main agent 
must indicate in the final summary that the review is incomplete.
 
           Context:
           - Repository: PLACEHOLDER_REPO
@@ -294,38 +339,47 @@ jobs:
           - Raw inline review comments JSON: 
PLACEHOLDER_CONTEXT_DIR/pr_review_comments.json
           - User review focus: PLACEHOLDER_CONTEXT_DIR/review_focus.txt
           - PR changed files: PLACEHOLDER_CONTEXT_DIR/pr_changed_files.txt
+          - Authoritative aggregate PR diff: PLACEHOLDER_CONTEXT_DIR/pr.diff
           - Required AGENTS.md files: 
PLACEHOLDER_CONTEXT_DIR/required_agents.txt
           - Shared subagent review ledger: 
PLACEHOLDER_CONTEXT_DIR/subagent_review_findings.md
 
+          PR diff and path-reading (for all subagents and the main agent):
+          - PLACEHOLDER_CONTEXT_DIR/pr.diff is the authoritative aggregate 
diff for the whole PR, and PLACEHOLDER_CONTEXT_DIR/pr_changed_files.txt is the 
authoritative changed-path list. Do not obtain the PR diff or changed-path list 
through other means.
+          - Before reading any file whose exact path is not already confirmed 
by PLACEHOLDER_CONTEXT_DIR/pr_changed_files.txt, 
PLACEHOLDER_CONTEXT_DIR/pr.diff, or a previous successful command output, you 
MUST first run `rg --files` to confirm the actual path of the target file.
+
           Before reviewing any code, you MUST read and follow the code review 
skill in this repository. During review, you must strictly follow those 
instructions.
           The active review goal's progress tracking MUST include, and must 
stay current throughout the review:
-          - Read the review prompt, code-review skill, required AGENTS.md 
files, existing review threads, user focus, changed-file list, and the shared 
subagent review ledger.
-          - Spawn the required focused subagents and assign each subagent a 
dedicated section in the shared ledger before it reviews.
-          - Require every subagent to append only to its assigned ledger 
section, while reading the whole ledger to avoid duplicate candidates.
-          - Read the shared ledger after every subagent result, then 
independently verify, deduplicate, accept, or dismiss every candidate in the 
main merged section.
-          - Run at least one final convergence round where every live subagent 
reviews the current ledger and proposed final comment set.
-          - Continue reviewing if any subagent reports a new valuable 
candidate during convergence; repeat verification and convergence until every 
subagent says `NO_NEW_VALUABLE_FINDINGS` for the same current ledger/comment 
set.
-          - Submit the final GitHub review and verify that all accepted 
comments landed before marking the goal complete.
-          The active review goal MUST remain incomplete until every suspicious 
point found during review has a clear conclusion: submitted as an inline issue, 
dismissed as already covered by existing review context, or dismissed with 
concrete code evidence explaining why it is not a bug.
-          You MUST use the available subagent or multi-agent spawn tool for 
this review; do not merely simulate subagent output in your own text. If tool 
discovery is needed, search for the subagent/multi-agent tool first. Spawn at 
least two subagents before final submission:
-          - one subagent assigned to the `optimizer-rewrite` ledger section 
and focused on optimizer/rewrite correctness, semantic equivalence, and 
parallel join/aggregate paths.
-          - one subagent assigned to the `tests-session-config` ledger section 
and focused on regression tests, expected outputs, session/config propagation, 
compatibility, and basic CI/style failures.
-          The shared subagent review ledger is 
PLACEHOLDER_CONTEXT_DIR/subagent_review_findings.md. Before spawning any 
subagent, the main agent MUST read this ledger. Every subagent prompt MUST 
include this ledger path and the exact ledger section assigned to that 
subagent. Subagents must read the whole ledger before reviewing, avoid 
duplicating existing candidates, and append their findings only under their 
assigned subagent section. They must not rewrite the whole ledger, edit another 
[...]
-          Each subagent must record candidate findings in its own ledger 
section with stable IDs, path/line, claim, evidence, duplicate relationship if 
any, and recommendation. If a candidate overlaps an existing ledger item, the 
subagent should add a duplicate note in its own section that references the 
existing candidate ID instead of modifying the existing candidate. This 
section-owned append-only rule is mandatory to avoid concurrent patch conflicts.
-          The main agent must read the shared ledger after each subagent 
result, merge duplicate candidates into the main merged section, update 
candidate statuses, and keep a proposed final comment set in the main-owned 
ledger sections. Statuses must distinguish at least: proposed_by_subagent, 
accepted_for_inline_comment, dismissed_with_evidence, 
duplicate_of_existing_thread, duplicate_of_candidate, and needs_more_evidence.
-          Before final submission, the main agent MUST send the current ledger 
and proposed final comment set to every live subagent and require a convergence 
response. A subagent may either append a new valuable candidate under its 
assigned section or reply exactly `NO_NEW_VALUABLE_FINDINGS` for the current 
ledger/comment set. The main agent MUST NOT complete the goal, final summary, 
or GitHub review until every live subagent has returned 
`NO_NEW_VALUABLE_FINDINGS` in the same convergen [...]
-          Subagents must only report candidate findings with evidence. The 
main agent must read their results and the shared ledger, independently verify 
or dismiss every candidate with concrete code evidence, deduplicate against 
existing review threads, and submit the final GitHub review itself. The final 
summary must include a short "Subagent conclusions" section describing which 
subagent candidates became inline comments, which were dismissed, which 
duplicates were merged, and which c [...]
-          If and only if the runtime exposes no subagent or multi-agent tool 
after explicit discovery, state that limitation in the final summary and 
continue the review manually.
-          You MUST NOT stop after finding the first blocking issue. Keep 
reviewing changed files, related control flow, tests, and parallel/special-case 
paths until all plausible correctness, lifecycle, configuration, compatibility, 
performance, and coverage bugs have been investigated and every bug you can 
substantiate has been reported.
-          Before submitting the final review, do one explicit final sweep over 
the changed-file list and your unresolved candidate list. Only finish when 
there are no unresolved suspicious points and all possible substantiated bugs 
have been pointed out in the GitHub review.
+          1. Read the review prompt, code-review skill, required AGENTS.md 
files, existing review threads, user focus, changed-file list, and the shared 
subagent review ledger.
+          2. Perform a main-agent initial risk scan before spawning review 
subagents. You must thoroughly read all the changes in this PR and understand 
all the involved mechanisms, pointing out: if there is a problem with this PR, 
where is the problem most likely to be? Or are there any points you suspect to 
be risky? write the result under `## Main Initial Risk Scan` in the shared 
ledger.
+          3. Based on the requirements of the code-review skill regarding the 
coverage points of the review spawn 1-3 subagents (depends on the complexity of 
the PR), each focusing on certain aspects. The sum of their focus points must 
fully cover the entire content of PR, as well as the points required in skill 
and any additional review points you consider necessary. They must complete the 
review of their own aspects and identify all possible issues before they can 
finish their work. Yo [...]
+          4. If the main initial risk scan identifies one or more suspicious 
mechanisms, spawn additional risk-focused subagent(s), separate from the normal 
complete-review subagents, to specially investigate those specific mechanisms 
and their upstream/downstream interactions.
+          5. Read the shared ledger after every subagent result, then 
independently verify, deduplicate, accept, or dismiss every candidate in the 
main merged section. The status of each candidate must be clarified after this 
stage.
+          6. If all subagents return `NO_NEW_VALUABLE_FINDINGS`, or if this 
loop has already executed 3 rounds, conduct the necessary review to ensure that 
all current candidate points have been verified, deduplicated, accepted, or 
rejected, and then submit the final GitHub comment. Otherwise, continue with 
the next round of the same review process from the beginning.
+          7. Submit the final GitHub review and verify that all accepted 
comments landed before marking the goal complete. You must address all 
checkpoints required by the skill, user concerns (if any), and indicate the 
status of the review completion.
+
+          Subagent Constraints:
+          - Every subagent appends only to its assigned ledger section, while 
reading the whole ledger to avoid duplicate candidates.
+          - Follow the principles indicated in the code-review skill.
+          - The shared subagent review ledger is 
PLACEHOLDER_CONTEXT_DIR/subagent_review_findings.md. Subagents must read the 
whole ledger before reviewing, avoid duplicating existing candidates, and 
append their findings only under their assigned subagent section. They must not 
rewrite the whole ledger, edit another subagent section, edit the main merged 
sections, edit repository source files, or submit GitHub comments.
+          - Each subagent must record candidate findings in its own ledger 
section with stable IDs, path/line, claim, evidence, duplicate relationship if 
any, and recommendation. Do not add duplicates of existing items. This 
section-owned append-only rule is mandatory to avoid concurrent patch conflicts.
+          - Before returning, a further thought must be made—what problem, if 
any, might I have missed just now, and where? Then a thorough recheck should be 
conducted to confirm whether this potential issue is real and whether it needs 
to be reported.
+
+          Main-agent Constraints:
+          - The active review goal MUST remain incomplete until every 
suspicious point found during review has a clear conclusion: submitted as an 
inline issue, dismissed as already covered by existing review context, or 
dismissed with concrete code evidence explaining why it is not a bug.
+          - The main initial risk scan MUST be written under `## Main Initial 
Risk Scan` in the shared ledger before any subagent is spawned. For every risk 
focus item, include: ID, changed files/lines involved, related mechanisms to 
inspect, why it is suspicious, required upstream/downstream files or paths, and 
the exact question the risk-focused subagent must answer.
+          - The shared subagent review ledger is 
PLACEHOLDER_CONTEXT_DIR/subagent_review_findings.md. Before spawning any 
subagent, the main agent MUST read this ledger. Every subagent prompt MUST 
include this ledger path and the exact ledger section assigned to that subagent.
+          - The main agent must read the shared ledger after each subagent 
result, merge duplicate candidates into the main merged section, update 
candidate statuses, and keep a proposed final comment set in the main-owned 
ledger sections. It must also update the status of every main risk focus item.
+          - Before submitting the final review, do one explicit final sweep 
over the changed-file list and your unresolved candidate list. Only finish when 
there are no unresolved suspicious points and all possible substantiated bugs 
have been pointed out in the GitHub review. At this stage, you can conduct 
final research on any part you still have doubts about or which may not have 
been fully investigated, ensuring that all potential issues have been 
thoroughly investigated and reported.
+
+          Any agent MUST NOT stop after finding the first blocking issue. Keep 
reviewing changed files, related control flow, tests, and parallel/special-case 
paths until all plausible correctness, lifecycle, configuration, compatibility, 
performance, and coverage bugs have been investigated and every bug you can 
substantiate has been reported.
+
           Before inspecting the PR diff or related code, you MUST read the 
contents of every AGENTS.md file listed below. These paths are computed from 
the PR changed file ancestors in this checkout. Searching for or listing paths 
is not sufficient; read each listed file directly.
           Required AGENTS.md files for this PR:
           PLACEHOLDER_REQUIRED_AGENTS_BLOCK
+
           Before proposing any new issue, you MUST read 
PLACEHOLDER_CONTEXT_DIR/pr_review_threads.md and treat every existing inline 
comment thread and reply as already-known review context.
-          Do NOT submit the same or substantially similar issue again if it 
has already been raised in the existing review threads, even if you would 
phrase it differently.
-          Only raise a similar concern when the PR introduces a genuinely 
different instance in another location that is not already covered by the 
existing thread, and explain why it is distinct.
-          You MUST also read PLACEHOLDER_CONTEXT_DIR/review_focus.txt. Perform 
a complete review of the whole PR as usual, and additionally pay special 
attention to the user-provided focus points from that file.
-          In the final summary, include a short response to the user focus 
points, including when no additional issue was found for them.
+          Do NOT submit the same or substantially similar issue again if it 
has already been raised in the existing review threads, even if you would 
phrase it differently. Only raise a similar concern when the PR introduces a 
genuinely different instance in another location that is not already covered by 
the existing thread, and explain why it is distinct.
+          You MUST also read PLACEHOLDER_CONTEXT_DIR/review_focus.txt. Perform 
a complete review of the whole PR as usual, and additionally pay special 
attention to the user-provided focus points from that file. In the final 
summary, include a short response to the user focus points, including when no 
additional issue was found for them.
           In addition, you can perform any desired review operations to 
observe suspicious code and details in order to identify issues as much as 
possible.
 
           ## Final response format
@@ -339,13 +393,14 @@ jobs:
               - Build a JSON array of comments like: [{ "path": "<file>", 
"position": <diff_position>, "body": "..." }]
               - Submit via: gh api 
repos/PLACEHOLDER_REPO/pulls/PLACEHOLDER_PR_NUMBER/reviews --input <json_file>
               - The JSON file should contain: 
{"event":"REQUEST_CHANGES","body":"<summary>","comments":[...]}
-          - A complete and detailed review of the entire PR must be conducted, 
identifying all potential issues and submitting corresponding comments. Only 
then can the review work be considered finished. If this standard is not 
strictly met, the review of the remaining parts must continue.
           PROMPT
+
           sed -i "s|PLACEHOLDER_REPO|${REPO}|g" 
"$REVIEW_CONTEXT_DIR/review_prompt.txt"
           sed -i "s|PLACEHOLDER_PR_NUMBER|${PR_NUMBER}|g" 
"$REVIEW_CONTEXT_DIR/review_prompt.txt"
           sed -i "s|PLACEHOLDER_HEAD_SHA|${HEAD_SHA}|g" 
"$REVIEW_CONTEXT_DIR/review_prompt.txt"
           sed -i "s|PLACEHOLDER_BASE_SHA|${BASE_SHA}|g" 
"$REVIEW_CONTEXT_DIR/review_prompt.txt"
           sed -i "s|PLACEHOLDER_CONTEXT_DIR|${REVIEW_CONTEXT_REL}|g" 
"$REVIEW_CONTEXT_DIR/review_prompt.txt"
+
           python3 - "$REVIEW_CONTEXT_DIR/review_prompt.txt" 
"$REVIEW_CONTEXT_DIR/required_agents_prompt.txt" <<'PY'
           import sys
           from pathlib import Path
@@ -368,15 +423,25 @@ jobs:
           - Subagents must not rewrite this file, edit another subagent 
section, edit main-owned sections, edit repository source files, or submit 
GitHub comments.
           - Avoid duplicates. If a candidate overlaps an existing candidate, 
add a duplicate note in your own section that references the existing candidate 
ID.
           - The main agent owns final status, final deduplication, GitHub 
review submission, and GitHub API verification.
-          - The goal is not complete until all live subagents have reviewed 
the current ledger and proposed final comment set in the same convergence round 
and replied `NO_NEW_VALUABLE_FINDINGS`.
+
+          ## Main Initial Risk Scan
+
+          Main-owned format:
+
+          - ID:
+            Status:
+            Changed files/lines:
+            Related mechanisms to inspect:
+            Why suspicious:
+            Required upstream/downstream files or paths:
+            Question for risk-focused subagent:
+            Final conclusion:
 
           Candidate statuses:
           - proposed_by_subagent
           - accepted_for_inline_comment
           - dismissed_with_evidence
-          - duplicate_of_existing_thread
-          - duplicate_of_candidate
-          - needs_more_evidence
+          - duplicated
 
           Candidate format:
 
@@ -390,18 +455,6 @@ jobs:
             Duplicate relationship:
             Recommendation:
 
-          ## Subagent Candidate Sections
-
-          ### optimizer-rewrite
-
-          Subagent assignment: optimizer/rewrite correctness, semantic 
equivalence, and parallel join/aggregate paths.
-          Append only below this line and above the next subagent heading.
-
-          ### tests-session-config
-
-          Subagent assignment: regression tests, expected outputs, 
session/config propagation, compatibility, and basic CI/style failures.
-          Append only below this line and above the main-owned sections.
-
           ## Main Merged Findings
 
           Main-owned format:
@@ -428,9 +481,7 @@ jobs:
           cat > "$REVIEW_CONTEXT_DIR/codex_goal_prompt.txt" <<EOF
           You are performing an automated code review inside a GitHub Actions 
runner.
           This invocation is already running in Codex goal mode. Before 
inspecting the PR diff or related code, read 
${REVIEW_CONTEXT_REL}/review_prompt.txt verbatim and follow that file as the 
complete review instruction set.
-          This review must use the available subagent or multi-agent spawn 
tool for focused review passes. All subagents and the main agent must maintain 
${REVIEW_CONTEXT_REL}/subagent_review_findings.md as the shared source of 
truth. Each subagent may append only to its assigned ledger section; the main 
agent owns merged statuses, duplicate suppression, proposed final comments, 
GitHub review submission, and GitHub API verification.
-          The review goal's completion process must include shared-ledger 
review, subagent spawning with assigned ledger sections, candidate 
verification, duplicate merge, a final subagent convergence round, GitHub 
review submission, and GitHub API verification. Do not complete the goal unless 
every live subagent has replied NO_NEW_VALUABLE_FINDINGS for the same current 
ledger/comment set after the last candidate update.
-          Keep reviewing until every suspicious point has a clear conclusion, 
every substantiated issue has been submitted as a GitHub inline review comment, 
and no new valuable review comment remains possible.
+          This document outlines the complete process, cyclic procedures, and 
exit agreements you need to follow. Please read it seriously and reconfirm the 
requirements at the end of each cycle. Complete the review according to the 
stipulations in this document.
           EOF
         env:
           REPO: ${{ github.repository }}
@@ -444,7 +495,6 @@ jobs:
         continue-on-error: true
         env:
           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          REASONING_EFFORT: xhigh
           REPO: ${{ github.repository }}
           PR_NUMBER: ${{ inputs.pr_number }}
           HEAD_SHA: ${{ inputs.head_sha }}
@@ -458,7 +508,7 @@ jobs:
           codex exec --goal "$GOAL_PROMPT" \
             --cd "$GITHUB_WORKSPACE" \
             --model "gpt-5.5" \
-            --config "model_reasoning_effort=\"${REASONING_EFFORT}\"" \
+            --config "model_reasoning_effort=xhigh" \
             --sandbox danger-full-access \
             --color never \
             --json \
@@ -531,7 +581,6 @@ jobs:
           HEAD_SHA: ${{ inputs.head_sha }}
           BASE_SHA: ${{ inputs.base_sha }}
           HELPER_REF: ${{ github.workflow_sha || github.sha }}
-          REASONING_EFFORT: xhigh
         run: |
           if [ ! -s "$REVIEW_CONTEXT_DIR/codex_goal_prompt.txt" ] || [ ! -s 
"$REVIEW_CONTEXT_DIR/codex-events.jsonl" ]; then
             echo "Goal prompt or Codex JSONL event stream is missing; skipping 
Litefuse I/O recording."
@@ -550,6 +599,8 @@ jobs:
             --events-file "$REVIEW_CONTEXT_DIR/codex-events.jsonl" \
             --output-file "$REVIEW_CONTEXT_DIR/codex-final-message.txt" \
             --trace-name "doris-ai-review" \
+            --subagent-trace-name "doris-ai-review-subagent" \
+            --subagent-sessions-dir "$CODEX_HOME/sessions" \
             --session-id "$GITHUB_RUN_ID" \
             --repository "$REPO" \
             --workflow "$GITHUB_WORKFLOW" \
@@ -558,7 +609,7 @@ jobs:
             --head-sha "$HEAD_SHA" \
             --base-sha "$BASE_SHA" \
             --model "gpt-5.5" \
-            --reasoning-effort "$REASONING_EFFORT" \
+            --reasoning-effort "xhigh" \
             --environment "github-actions" \
             --max-payload-bytes 4000000 \
             --min-observations 4 \
diff --git a/be/src/core/AGENTS.md b/be/src/core/AGENTS.md
index b31c1afad0d..3380ea50285 100644
--- a/be/src/core/AGENTS.md
+++ b/be/src/core/AGENTS.md
@@ -12,12 +12,30 @@ Types in `be/src/core/custom_allocator.h` exist to route 
owned memory through Do
 
 Vectorized columns (`IColumn`) use intrusive-reference-counted copy-on-write.
 
+### Standard Use Pattern
+
+1. For newly created columns locally: Prefer to directly retain the original 
`MutableColumnPtr` if possible. Use `assume_mutable()` if necessary.
+2. For shared or unknown ownership `ColumnPtr`: Use `IColumn::mutate(...)` and 
write back the owner.
+3. When modifying the entire `Block` or `Column`: Prefer using 
`mutate_columns_scoped()` or `mutate_column_scoped(pos)`.
+4. When applying an algorithm to a `Block` using `MutableBlock`: Understand 
the potential for detachment, then use `ScopedMutableBlock` or 
`VectorizedUtils::build_scoped_mutable_mem_reuse_block(...)`.
+5. Row-level loops: Do not mutate the block or columns row by row. Obtain the 
mutable owners all at once.
+6. Modifying columns of complex types: First mutate the parent owner. Do not 
force clone to satisfy mutable access. Only detach when it is definitely 
necessary to modify.
+
+Avoid anti-patterns:
+
+1. Do not use `IColumn::mutate` to modify and write back a column in a 
`Block`; instead, use `mutate_column_scoped`.
+2. Do not call `Block::get_columns()` directly on a `Block` before mutation.
+3. Do not use `assert_mutable()` if ownership is not clearly defined; instead, 
use `mutate` and understand the possibility of detach.
+4. Do not `mutate()` row by row.
+5. Do not call `ScopedMutableColumns::release()` unless it is a special 
scenario requiring temporary transfer of ownership.
+
 ### Checkpoints
 
 - [ ] Exclusive ownership guaranteed before `mutate()` on hot paths? Shared 
ownership triggers deep copy
 - [ ] `assert_mutable()` used only when exclusive ownership is already 
guaranteed?
 - [ ] If you need to modify the data within a `Block`, have you correctly used 
`ScopedMutableBlock`?
 - [ ] `convert_to_full_column_if_const()` materializes only `ColumnConst`; 
ordinary columns may return shared storage?
+- [ ] If a `Block` is still going to be used later, and we temporarily need to 
use its column externally,should we prefer to copy rather than `std::move` its 
`ColumnPtr`? If moving is necessary, are they all put back before all exits?
 
 ## Type System and Serialization
 
diff --git a/be/src/format/table/jdbc_jni_reader.cpp 
b/be/src/format/table/jdbc_jni_reader.cpp
index badb3177803..0fc54e58e74 100644
--- a/be/src/format/table/jdbc_jni_reader.cpp
+++ b/be/src/format/table/jdbc_jni_reader.cpp
@@ -190,7 +190,7 @@ Status JdbcJniReader::_cast_string_to_special_type(const 
SlotDescriptor* slot_de
 
     ColumnsWithTypeAndName argument_template;
     argument_template.reserve(2);
-    argument_template.emplace_back(std::move(input_col), input_string_type, 
"java.sql.String");
+    argument_template.emplace_back(input_col, input_string_type, 
"java.sql.String");
     argument_template.emplace_back(cast_param, cast_param_data_type, 
target_data_type_name);
 
     FunctionBasePtr func_cast = SimpleFunctionFactory::instance().get_function(


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to