v_task_detail.html 13.4 KB
<!DOCTYPE html>
<!--
  v_task_detail — 静态原型,对应 02-V §2.6,路由 /tasks/:task_id
  内嵌 v_graph_visualizer(§2.7,详细独立示范见 v_graph_visualizer.html)+ v_log_viewer(§2.7.1)
  这是"检查过程"诉求的核心落地页面,多个子模块嵌套,值得完整画出。
-->
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>graphlemon · 任务详情</title>
<style>
:root { --brand:#4f46e5; --border:#e5e7eb; --text:#111827; --text-muted:#6b7280; --bg:#fff; --bg-panel:#f9fafb;
  --status-pending:#9ca3af; --status-running:#3b82f6; --status-reflecting:#eab308; --status-waiting-quota:#7dd3fc; --status-blocked:#ef4444; --status-done:#22c55e; }
* { box-sizing: border-box; }
body { font-family:-apple-system,sans-serif; margin:0; color:var(--text); background:var(--bg); }
.proto-banner { background:#fef3c7; border-bottom:1px solid #f59e0b; padding:6px 20px; font-size:12px; }
.app-nav { display:flex; align-items:center; gap:4px; padding:0 20px; height:52px; border-bottom:1px solid var(--border); position:sticky; top:0; background:#fff; z-index:10;}
.app-nav .brand { font-weight:700; margin-right:20px; color:var(--brand); }
.app-nav a.nav-link { padding:8px 12px; border-radius:6px; color:var(--text); text-decoration:none; font-size:14px; }
.app-nav a.nav-link:hover, .app-nav a.nav-link.active { background:var(--bg-panel); color:var(--brand); }
.app-nav .nav-dropdown { position:relative; }
.app-nav .nav-dropdown > span { padding:8px 12px; border-radius:6px; font-size:14px; cursor:pointer; display:inline-block; }
.app-nav .dropdown-menu { display:none; position:absolute; top:100%; left:0; background:#fff; border:1px solid var(--border); border-radius:8px; padding:6px; min-width:160px; box-shadow:0 4px 12px rgba(0,0,0,.08); }
.app-nav .nav-dropdown:hover .dropdown-menu { display:block; }
.app-nav .dropdown-menu a { display:block; padding:6px 10px; border-radius:4px; color:var(--text); text-decoration:none; font-size:13px; }
.app-nav .nav-project { margin-left:auto; font-size:13px; color:var(--text-muted); }
.app-nav .nav-project a { color:var(--brand); text-decoration:none; margin-left:6px; }
.page { padding:24px; max-width:1200px; margin:0 auto; }
.breadcrumb { font-size:13px; color:var(--text-muted); margin-bottom:6px; }
.breadcrumb a { color:var(--text-muted); }
h1 { font-size:20px; margin:0 0 4px; }
.alert-banner { background:#fef2f2; border:1px solid #fecaca; color:#991b1b; border-radius:8px; padding:12px 14px; font-size:13px; margin:14px 0; display:flex; justify-content:space-between; align-items:center; }
.btn { display:inline-block; padding:7px 14px; border-radius:6px; border:1px solid var(--border); background:#fff; font-size:13px; cursor:pointer; text-decoration:none; color:var(--text); }
.btn-danger { background:#dc2626; border-color:#dc2626; color:#fff; }
.panel { border:1px solid var(--border); border-radius:10px; padding:18px; background:var(--bg-panel); margin:16px 0; }
.panel h2 { font-size:13px; text-transform:uppercase; letter-spacing:.04em; color:var(--text-muted); margin:0 0 14px; }
.meta-row { display:flex; gap:28px; font-size:13px; margin-bottom:6px; }
.meta-row b { display:block; font-size:11px; color:var(--text-muted); font-weight:600; }

/* Org Graph 条 */
.org-strip { display:flex; align-items:center; gap:0; margin-bottom:6px; }
.org-node { border:2px solid var(--border); border-radius:8px; padding:8px 16px; text-align:center; background:#fff; flex:1; font-size:12px; }
.org-node.active { border-color:var(--status-running); background:#eff6ff; }
.org-arrow { flex:0 0 24px; text-align:center; color:var(--text-muted); }

.see-more { font-size:12px; }
.see-more a { color:var(--brand); }

/* to-do 树(新增,2026-07-30,对应 01-M work_graph_run.graph_manifest 补充说明 + 02-V §2.6)
   graph_manifest 本身就是 to-do list:树的节点 = graph_manifest 的节点,缩进 = fan-out/fan-in 依赖分组。
   这棵树只属于「这一个 task 的这一次 coder work_graph_run」,不是多个 task 组成的树。 */
.todo-tree-label { font-size:11px; color:var(--text-muted); margin-bottom:8px; }
.todo-tree { list-style:none; margin:0 0 4px; padding:0; font-size:13px; }
.todo-tree li { position:relative; padding:6px 0 6px 22px; border-left:1px dashed var(--border); margin-left:8px; }
.todo-tree li:last-child { border-left-color:transparent; }
.todo-tree li::before { content:""; position:absolute; left:0; top:16px; width:14px; height:1px; background:var(--border); }
.todo-tree .todo-row { display:flex; align-items:center; gap:8px; cursor:pointer; }
.todo-tree .dot { width:9px; height:9px; border-radius:50%; border:2px solid var(--status-pending); flex:0 0 auto; }
.todo-tree li.status-done .dot { border-color:var(--status-done); background:var(--status-done); }
.todo-tree li.status-running .dot { border-color:var(--status-running); background:var(--status-running); }
.todo-tree li.status-reflecting .dot { border-color:var(--status-reflecting); background:var(--status-reflecting); }
.todo-tree li.status-waiting_for_quota .dot { border-color:var(--status-waiting-quota); background:var(--status-waiting-quota); }
.todo-tree li.status-blocked .dot, .todo-tree li.status-failed .dot { border-color:var(--status-blocked); background:var(--status-blocked); }
.todo-tree .todo-id { font-weight:600; }
.todo-tree .todo-skill { color:var(--text-muted); font-size:11px; }
.todo-tree .todo-status { margin-left:auto; font-size:11px; color:var(--text-muted); }
.todo-tree ul { list-style:none; margin:2px 0 0; padding:0; }
.todo-detail { display:none; margin:6px 0 0 17px; padding:8px 10px; background:#fff; border:1px solid var(--border); border-radius:6px; font-size:12px; color:var(--text-muted); }
.todo-detail.open { display:block; }
.todo-detail a { color:var(--brand); text-decoration:none; }

/* Artifact / bug list */
ul.simple-list { list-style:none; margin:0; padding:0; font-size:13px; }
ul.simple-list li { padding:8px 0; border-bottom:1px solid var(--border); display:flex; justify-content:space-between; }
ul.simple-list li:last-child { border-bottom:none; }
ul.simple-list a { color:var(--brand); text-decoration:none; }

/* 日志查看器 v_log_viewer,§2.7.1 */
.log-viewer { background:#0b1120; color:#d1d5db; font-family:ui-monospace,monospace; font-size:12px; border-radius:8px; padding:14px; max-height:220px; overflow:auto; }
.log-viewer .line { white-space:pre-wrap; line-height:1.6; }
.log-toolbar { display:flex; justify-content:space-between; align-items:center; margin-bottom:8px; font-size:12px; }
.log-toolbar label { display:flex; align-items:center; gap:6px; color:var(--text-muted); }
</style>
</head>
<body>
<div class="proto-banner">静态原型(mock 数据)· 对应 02-V §2.6/§2.7/§2.7.1 · 内嵌 v_graph_visualizer + v_log_viewer</div>
<nav class="app-nav">
  <div class="brand">graphlemon</div>
  <a href="v_dashboard.html" class="nav-link">仪表盘</a>
  <a href="v_task_board.html" class="nav-link active">任务</a>
  <a href="v_artifact_browser.html" class="nav-link">产物</a>
  <a href="v_skill_library.html" class="nav-link">技能库</a>
  <div class="nav-dropdown"><span>设置</span>
    <div class="dropdown-menu">
      <a href="v_concurrency_settings.html">并发数</a>
      <a href="v_budget_settings.html">预算护栏</a>
      <a href="v_log_retention_settings.html">日志保留</a>
    </div>
  </div>
  <div class="nav-project">当前项目:snake-game <a href="v_project_setup.html">切换</a></div>
</nav>

<div class="page">
  <div class="breadcrumb"><a href="v_task_board.html">任务</a> / task-7a02</div>
  <h1>修复撞墙判定 off-by-one</h1>

  <!-- blocked_pending_human 醒目告警样式,见 02-V §2.6 异常态 -->
  <div class="alert-banner">
    ⚠ 已达 loop_round 上限(3 轮),转 blocked_pending_human,需要人工干预
    <a class="btn btn-danger" href="v_task_board.html">人工干预(manual_resume)</a>
  </div>

  <div class="meta-row">
    <div><b>STATUS</b>blocked_pending_human</div>
    <div><b>LOOP_ROUND</b>3</div>
    <div><b>ASSIGNED_ORG_NODE</b>coder</div>
    <div><b>CREATED_VIA</b>human_console</div>
  </div>

  <div class="panel">
    <h2>Org Graph(3 个固定节点,高亮当前所处节点)</h2>
    <div class="org-strip">
      <div class="org-node active">Planner</div><div class="org-arrow">→</div>
      <div class="org-node active">Coder</div><div class="org-arrow">→</div>
      <div class="org-node">Validator</div>
    </div>
  </div>

  <!--
    to-do 树(新增,2026-07-30)—— 对应 01-M work_graph_run.graph_manifest 的补充说明 + 02-V §2.6:
    这棵树渲染的就是 org_node=coder 这一次 work_graph_run.graph_manifest 本身(即 to-do list),
    不是新的实体、也不是多个 task 组成的树。缩进 = fan-out/fan-in 依赖分组,圆点颜色 = work_node_execution.status。
    层级:project → task(本页) → work_graph_run(org_node=coder) → 下面这棵 to-do 树 → work_node_execution → execution_log_file
  -->
  <div class="panel">
    <h2>Coder Work Graph 的 to-do 树(本次 work_graph_run.graph_manifest,graph_manifest = to-do list)</h2>
    <div class="todo-tree-label">来源:work_graph_run(org_node=coder,run_id=run-coder-014)· 点击节点展开 work_node_execution 详情</div>
    <ul class="todo-tree">
      <li class="status-done">
        <div class="todo-row" onclick="toggleTodo('t-collision')">
          <span class="dot"></span>
          <span class="todo-id">to-do: collision-check</span>
          <span class="todo-skill">skill: code-task-development</span>
          <span class="todo-status">done · node_exec_id=node-001</span>
        </div>
        <div class="todo-detail" id="t-collision">
          input_schema_ref: sdd_module.schema.json · output_schema_ref: code_diff.schema.json · retry_count: 0<br>
          <a href="#" onclick="event.stopPropagation()">展开 v_log_viewer 原始日志 →</a>
        </div>
      </li>
      <li class="status-reflecting">
        <div class="todo-row" onclick="toggleTodo('t-score')">
          <span class="dot"></span>
          <span class="todo-id">to-do: score-board</span>
          <span class="todo-skill">skill: debugging-toolkit</span>
          <span class="todo-status">reflecting · node_exec_id=node-002 · retry 3/5</span>
        </div>
        <div class="todo-detail open" id="t-score">
          reflection_notes: 撞墙判定用 &gt; 而不是 &gt;=,unit test 断言未通过;准备第 4 轮重试<br>
          <a href="#" onclick="event.stopPropagation()">展开 v_log_viewer 原始日志 →</a>(见下方,已展开)
        </div>
        <ul>
          <li class="status-pending">
            <div class="todo-row" onclick="toggleTodo('t-score-retry')">
              <span class="dot"></span>
              <span class="todo-id">依赖:等待 score-board 修复后再跑 integration test</span>
              <span class="todo-status">fan-in 等待中</span>
            </div>
            <div class="todo-detail" id="t-score-retry">这一项是 fan-in:integration-test 节点,等待 score-board 和 input-handler 都到达 done 才会开始。</div>
          </li>
        </ul>
      </li>
      <li class="status-waiting_for_quota">
        <div class="todo-row" onclick="toggleTodo('t-input')">
          <span class="dot"></span>
          <span class="todo-id">to-do: input-handler</span>
          <span class="todo-skill">skill: code-agent-engineering</span>
          <span class="todo-status">waiting_for_quota(自愈型,非告警)· 已等待 12 分钟</span>
        </div>
        <div class="todo-detail" id="t-input">
          quota_limit_type: session · 退避重试中,不计入 retry_count(03-C §3.6)<br>
          <a href="#" onclick="event.stopPropagation()">展开 v_log_viewer 原始日志 →</a>
        </div>
      </li>
    </ul>
    <div class="see-more"><a href="v_graph_visualizer.html">查看按执行层级排布的 DAG 视图(v_graph_visualizer,同一份 graph_manifest 的另一种呈现)→</a></div>
  </div>

  <div class="panel">
    <h2>关联 Artifact</h2>
    <ul class="simple-list">
      <li><a href="v_artifact_browser.html">sdd_v2.md</a><span>产出于 planner work_graph_run</span></li>
      <li><a href="v_artifact_browser.html">code_diff_collision.patch</a><span>产出于 coder work_graph_run</span></li>
    </ul>
  </div>

  <div class="panel">
    <h2>关联 Bug 记录</h2>
    <ul class="simple-list">
      <li>root_cause_category = coder:撞墙判定用 &gt; 而不是 &gt;=<span>root_cause_detail 链接</span></li>
    </ul>
  </div>

  <div class="panel">
    <h2>原始执行日志(v_log_viewer,node_exec_id = node-002)</h2>
    <div class="log-toolbar">
      <label><input type="checkbox" checked> 自动滚动到最新</label>
      <a class="btn" href="#">下载完整日志</a>
    </div>
    <div class="log-viewer">
      <div class="line">[12:04:01] Coder 认领 task-7a02,读取 SDD §4.2 撞墙判定规则</div>
      <div class="line">[12:04:03] 修改 game_logic.py: is_collision() 边界判断</div>
      <div class="line">[12:04:20] 运行 python3 -m unittest test_game_logic.py</div>
      <div class="line">[12:04:21] FAILED: test_wall_collision_off_by_one (仍未修复)</div>
      <div class="line">[12:04:22] reflection: 差距未闭合,准备第 4 轮重试……</div>
    </div>
  </div>
</div>
<script>
  // 真实实现里点击 to-do 行 = click_view_raw_log / 展开 work_node_execution 详情(02-V §2.6)
  function toggleTodo(id) {
    document.getElementById(id).classList.toggle('open');
  }
</script>
</body>
</html>