data-documents.html 13.5 KB
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" />
<title>四类文档 · LemonBoss PRD</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,500;9..144,700&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="assets/shell.css" />
</head>
<body data-page="data-documents.html">
<div class="shell">
  <aside id="sidebar"></aside>
  <main class="page">
    <header class="page-head">
      <div class="crumb"><span class="pill">05 · DATA</span><span class="sep">/</span><span>四类文档</span></div>
      <h1>四类文档</h1>
      <p class="deck">PRD / SDD / units.json / runs/result.json — 它们之间是<b>派生关系</b>,构成系统的唯一真源。本页给出完整 schema 与示例。</p>
    </header>
    <article class="body">

      <section>
        <h2>派生关系</h2>
        <svg viewBox="0 0 1100 220" width="100%" role="img">
          <defs><marker id="arrD" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0,0 L10,5 L0,10 Z" fill="#0E0E10"/></marker></defs>
          <g font-family="JetBrains Mono" font-size="11" fill="#0E0E10">
            <rect x="40"  y="80" width="180" height="60" rx="6" fill="#ECE4FB" stroke="#6E48C3"/>
            <text x="130" y="110" text-anchor="middle" font-weight="700">prd.html</text>
            <text x="130" y="128" text-anchor="middle" font-size="10">人类需求</text>

            <rect x="280" y="80" width="180" height="60" rx="6" fill="#fff" stroke="#0E0E10"/>
            <text x="370" y="110" text-anchor="middle" font-weight="700">sdd.html</text>
            <text x="370" y="128" text-anchor="middle" font-size="10">含可机读 unit metadata</text>

            <rect x="520" y="30" width="180" height="60" rx="6" fill="#fff" stroke="#0E0E10"/>
            <text x="610" y="60" text-anchor="middle" font-weight="700">units.json</text>
            <text x="610" y="78" text-anchor="middle" font-size="10">DAG 索引</text>

            <rect x="520" y="130" width="180" height="60" rx="6" fill="#fff" stroke="#0E0E10"/>
            <text x="610" y="160" text-anchor="middle" font-weight="700">integration/spec.json</text>
            <text x="610" y="178" text-anchor="middle" font-size="10">端到端测试用例</text>

            <rect x="760" y="80" width="180" height="60" rx="6" fill="#E2F2EA" stroke="#0E8C5A"/>
            <text x="850" y="110" text-anchor="middle" font-weight="700">runs/*/result.json</text>
            <text x="850" y="128" text-anchor="middle" font-size="10">执行产物</text>

            <g stroke="#0E0E10" fill="none" marker-end="url(#arrD)">
              <line x1="220" y1="110" x2="275" y2="110"/>
              <line x1="460" y1="100" x2="515" y2="60"/>
              <line x1="460" y1="120" x2="515" y2="160"/>
              <line x1="700" y1="60" x2="755" y2="100"/>
              <line x1="700" y1="160" x2="755" y2="120"/>
            </g>
          </g>
        </svg>
      </section>

      <section>
        <h2>四个文档逐一</h2>
        <div class="tabs" data-tabs>
          <div class="tabbar" role="tablist">
            <button role="tab" aria-selected="true"  aria-controls="t-prd">prd.html</button>
            <button role="tab" aria-selected="false" aria-controls="t-sdd">sdd.html</button>
            <button role="tab" aria-selected="false" aria-controls="t-units">units.json</button>
            <button role="tab" aria-selected="false" aria-controls="t-run">runs/result.json</button>
          </div>
          <div class="tabpanel" id="t-prd">
<pre class="code"><span class="c">&lt;!-- PM Agent 维护,每次人类反馈追加 section --&gt;</span>
<span class="k">&lt;article</span> <span class="n">data-doc</span>=<span class="s">"prd"</span> <span class="n">data-rev</span>=<span class="s">"3"</span><span class="k">&gt;</span>
  <span class="k">&lt;h1&gt;</span><span class="v">Auto Auth System</span><span class="k">&lt;/h1&gt;</span>

  <span class="k">&lt;section</span> <span class="n">data-rev</span>=<span class="s">"1"</span><span class="k">&gt;</span>
    <span class="k">&lt;h3&gt;</span><span class="v">登录</span><span class="k">&lt;/h3&gt;</span>
    <span class="k">&lt;p&gt;</span><span class="v">用户名密码登录,会话 7 天有效。</span><span class="k">&lt;/p&gt;</span>
  <span class="k">&lt;/section&gt;</span>

  <span class="k">&lt;section</span> <span class="n">data-rev</span>=<span class="s">"3"</span> <span class="n">data-origin</span>=<span class="s">"yibo@2026-05-13"</span><span class="k">&gt;</span>
    <span class="k">&lt;h3&gt;</span><span class="v">OAuth 登录</span><span class="k">&lt;/h3&gt;</span>
    <span class="k">&lt;p&gt;</span><span class="v">支持 GitHub OAuth。Token 刷新 ≤ 5s。</span><span class="k">&lt;/p&gt;</span>
  <span class="k">&lt;/section&gt;</span>

  <span class="k">&lt;footer</span> <span class="n">data-changelog</span><span class="k">&gt;</span>
    <span class="k">&lt;p&gt;</span><span class="v">rev 1 · init · 邮箱密码登录</span><span class="k">&lt;/p&gt;</span>
    <span class="k">&lt;p&gt;</span><span class="v">rev 2 · yibo · 加个人主页</span><span class="k">&lt;/p&gt;</span>
    <span class="k">&lt;p&gt;</span><span class="v">rev 3 · yibo · GitHub OAuth</span><span class="k">&lt;/p&gt;</span>
  <span class="k">&lt;/footer&gt;</span>
<span class="k">&lt;/article&gt;</span></pre>
          </div>
          <div class="tabpanel" id="t-sdd" hidden>
<pre class="code"><span class="c">&lt;!-- Architect 生成;嵌入可机读 unit 元数据 --&gt;</span>
<span class="k">&lt;article</span> <span class="n">data-doc</span>=<span class="s">"sdd"</span> <span class="n">data-derived-from</span>=<span class="s">"prd@rev3"</span><span class="k">&gt;</span>
  <span class="k">&lt;section</span> <span class="n">data-unit-id</span>=<span class="s">"auth-be"</span> <span class="n">data-type</span>=<span class="s">"be"</span>
           <span class="n">data-depends</span>=<span class="s">""</span><span class="k">&gt;</span>
    <span class="k">&lt;h3&gt;</span><span class="v">Unit · auth-be</span><span class="k">&lt;/h3&gt;</span>
    <span class="k">&lt;p&gt;</span><span class="v">提供登录 / 注册 / token 校验端点</span><span class="k">&lt;/p&gt;</span>
    <span class="k">&lt;pre</span> <span class="n">data-contract</span>=<span class="s">"openapi"</span><span class="k">&gt;</span>
      <span class="v">POST /api/auth/login</span>
      <span class="v">  request:  { email, password }</span>
      <span class="v">  response: 200 { token } | 401 { error:"invalid_credentials" }</span>
    <span class="k">&lt;/pre&gt;</span>
    <span class="k">&lt;ul</span> <span class="n">data-acceptance</span><span class="k">&gt;</span>
      <span class="k">&lt;li&gt;</span><span class="v">有效凭据 → 200 + JWT</span><span class="k">&lt;/li&gt;</span>
      <span class="k">&lt;li&gt;</span><span class="v">user 不存在 → 401 invalid_credentials</span><span class="k">&lt;/li&gt;</span>
    <span class="k">&lt;/ul&gt;</span>
  <span class="k">&lt;/section&gt;</span>
  <span class="c">&lt;!-- 更多 section ... --&gt;</span>
<span class="k">&lt;/article&gt;</span></pre>
          </div>
          <div class="tabpanel" id="t-units" hidden>
<pre class="code"><span class="p">{</span>
  <span class="n">"project_id"</span>: <span class="s">"p-001"</span>,
  <span class="n">"prd_rev"</span>: <span class="s">"3"</span>,
  <span class="n">"sdd_rev"</span>: <span class="s">"5"</span>,
  <span class="n">"units"</span>: <span class="p">[</span>
    <span class="p">{</span>
      <span class="n">"id"</span>: <span class="s">"auth-be"</span>,
      <span class="n">"type"</span>: <span class="s">"be"</span>,
      <span class="n">"status"</span>: <span class="s">"passed"</span>,
      <span class="n">"depends_on"</span>: <span class="p">[]</span>,
      <span class="n">"retries"</span>: <span class="v">1</span>,
      <span class="n">"retry_budget"</span>: <span class="v">5</span>,
      <span class="n">"contract_hash"</span>: <span class="s">"sha256:7f3a..."</span>,
      <span class="n">"last_run"</span>: <span class="s">"run-20260513-0731"</span>
    <span class="p">}</span>,
    <span class="p">{</span>
      <span class="n">"id"</span>: <span class="s">"auth-fe"</span>,
      <span class="n">"type"</span>: <span class="s">"fe"</span>,
      <span class="n">"status"</span>: <span class="s">"testing"</span>,
      <span class="n">"depends_on"</span>: <span class="p">[</span><span class="s">"auth-be"</span><span class="p">]</span>,
      <span class="n">"retries"</span>: <span class="v">0</span>,
      <span class="n">"retry_budget"</span>: <span class="v">5</span>,
      <span class="n">"contract_hash"</span>: <span class="s">"sha256:9c1d..."</span>
    <span class="p">}</span>
  <span class="p">]</span>,
  <span class="n">"l2_rounds"</span>: <span class="v">0</span>,
  <span class="n">"l2_budget"</span>: <span class="v">3</span>
<span class="p">}</span></pre>
          </div>
          <div class="tabpanel" id="t-run" hidden>
<pre class="code"><span class="p">{</span>
  <span class="n">"run_id"</span>: <span class="s">"run-20260513-0731"</span>,
  <span class="n">"loop"</span>: <span class="s">"L1"</span>,
  <span class="n">"unit_id"</span>: <span class="s">"auth-be"</span>,
  <span class="n">"agent"</span>: <span class="s">"tester"</span>,
  <span class="n">"attempt"</span>: <span class="v">2</span>,
  <span class="n">"summary"</span>: <span class="p">{</span> <span class="n">"total"</span>: <span class="v">8</span>, <span class="n">"passed"</span>: <span class="v">7</span>, <span class="n">"failed"</span>: <span class="v">1</span> <span class="p">}</span>,
  <span class="n">"ok"</span>: <span class="v">false</span>,
  <span class="n">"failures"</span>: <span class="p">[</span>
    <span class="p">{</span> <span class="n">"test"</span>: <span class="s">"login.invalid-pwd"</span>,
      <span class="n">"expected"</span>: <span class="v">401</span>, <span class="n">"got"</span>: <span class="v">500</span>,
      <span class="n">"stack"</span>: <span class="s">"TypeError: ..."</span>,
      <span class="n">"hint"</span>: <span class="s">"先查 user 再 bcrypt 比对"</span> <span class="p">}</span>
  <span class="p">]</span>,
  <span class="n">"next_action"</span>: <span class="s">"retry_coder"</span>,
  <span class="n">"retry_budget_left"</span>: <span class="v">3</span>,
  <span class="n">"duration_ms"</span>: <span class="v">1245</span>
<span class="p">}</span></pre>
          </div>
        </div>
      </section>

      <section>
        <h2>谁能写谁</h2>
        <table class="dense">
          <thead><tr><th>文档</th><th>写入者</th><th>读取者</th></tr></thead>
          <tbody>
            <tr><td><code>prd.html</code></td><td>PM (通过 DocStore)</td><td>Architect · Dashboard</td></tr>
            <tr><td><code>sdd.html</code></td><td>Architect (通过 DocStore)</td><td>Coder · Tester · Integrator · Triager · Dashboard</td></tr>
            <tr><td><code>units.json</code></td><td>Architect (字段) + UnitRegistry (status)</td><td>所有</td></tr>
            <tr><td><code>integration/spec.json</code></td><td>Architect</td><td>Integrator</td></tr>
            <tr><td><code>units/{id}/code/**</code></td><td>Coder</td><td>Tester · Integrator · Triager (只读)</td></tr>
            <tr><td><code>units/{id}/contract.json</code></td><td>Coder</td><td>Tester · 其他 Unit Coder · Triager</td></tr>
            <tr><td><code>units/{id}/tests/**</code></td><td>Tester</td><td>Integrator</td></tr>
            <tr><td><code>runs/{id}/result.json</code></td><td>Tester (L1) / Integrator (L2)</td><td>LoopController · Triager · Dashboard</td></tr>
            <tr><td><code>triage.json</code></td><td>BugTriager</td><td>LoopController · Architect</td></tr>
            <tr><td><code>history/**</code></td><td>DocStore.archive()</td><td>Dashboard diff 视图</td></tr>
            <tr><td><code>agent-state/{agent}.json</code></td><td>LoopController + Agent 工具</td><td>Dashboard · recoverOnBoot</td></tr>
            <tr><td><code>agent-state/{agent}-todo.json</code></td><td>Agent (write_todolist · update_todo_item 工具)</td><td>Dashboard · getProgress</td></tr>
            <tr><td><code>agent-state/snapshots/*</code></td><td>LoopController</td><td>retry 时回放 · recover</td></tr>
            <tr><td><code>timeline.ndjson</code></td><td>TimelineLogger (所有 source append)</td><td>Dashboard 时间线 · audit</td></tr>
            <tr><td><code>memory/devloop/{agent}/*.md</code></td><td>Agent (record_memory 工具)</td><td>Agent 启动时注入 prompt</td></tr>
          </tbody>
        </table>
      </section>

      <section>
        <h2>归档策略</h2>
        <p>每次 prd / sdd / units.json 被写时,旧版本自动移到 <code>history/</code>,命名规则:</p>
        <ul>
          <li><code>history/prd-rev-{N}.html</code></li>
          <li><code>history/sdd-rev-{N}.html</code></li>
          <li><code>history/units-rev-{N}.json</code></li>
        </ul>
        <p>Dashboard 的 PRD diff 视图直接读 history 做 section diff。无需 git。</p>
      </section>

    </article>
    <nav class="prev-next"></nav>
    <footer class="site"><div><b>Section</b>05 · Data</div><div><b>Page</b>data-documents.html</div></footer>
  </main>
</div>
<script src="assets/shell.js"></script>
</body>
</html>