• 在 prd-planning/agent.md 加了「描述性语言扫描」+「内容深度下限」+「业务度量翻译」三段
    具体操作(对应 36 号文档训练出的 SKILL.md Step 4/5),soul.md 加一条对应工作原则。
    用同一个 e2e-demo 首页任务重新跑了一次端到端回归验证:新 PRD 把"大图/简洁大气"等形容词
    逐条翻译成量化规则,最终产出的 index.html/style.css 精确对应这些数值(视觉元素
    min-height:320px、区块间距 96px/56px 等),文案不再卡在"非空"这条线——训练效果在
    真实任务里得到验证。
    
    回归过程中发现一个新的、独立于本次改动的引擎缺陷:org-coder-test 被反向打回后产出
    「建议重跑 org-coder-validator」的诊断文件,引擎把诊断文件里的 infra_flake 标记当成
    了这个节点自己的执行结果,导致原地重跑但从不路由到诊断建议的目标节点,陷入没有熔断线
    的确定性死循环。记进 30 号文档,留待后续修复。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 新建独立试验节点 prd-methodology-trial,走真实 Hunt→Digest→Evolve 训练 PRD 撰写方法论:
    2 轮 Small Loop 提前收敛(96/97 分,真实基线 50 分),用三个真实历史项目反推验证方法论
    有效,Deploy 范围限定在该独立节点,未触碰生产 prd-planning。结论:FDE 对方法论类角色
    确实管用,但收敛速度/验收严谨度依赖任务书里显式写明的自纠正要求,非免人工黑盒。
    
    过程中连带修复同一个 2026-08-16 改名批次(innovator→org-innovator 等)遗留的 5 处死链:
    company.js 两处硬编码调用、CompanyDashboard.vue「重新训练」按钮,以及四个本体各自
    config.json 内部 id 字段从未随目录改名同步更新,导致 /api/agent/list 展示层用假 id
    显示成死卡片。顺手修了 AgentScaffold 默认 tools.md 模板一处裸相对路径缺陷(对应
    agent-md-refs.test.js 里已登记多时的已知缺陷)。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »

  • 补记 commit fadb6fa 的实现记录:证据闸门选了"拦截"不是"降级"(降级等于还是采信
    了分数,只是换个说法);goal-benchmark.json schema 完全不用改,evidence 早就是
    benchmark-validator/agent.md 教的既有字段,只是从没被 goal-contract.js run 读过,
    让 runBenchmark 多看一眼姊妹判词文件即可,没有发明新格式;C 的实现只更新了真正
    写分数/证据的 benchmark-validator,不是最初以为的 coder/unit-tester。
    
    §三推进顺序标注全部完成,并记录了样本量不足的遗留风险(只有一次真实回归验证过
    证据闸门,关键词表覆盖度与拦截后的连带影响都还没有大量数据支撑)。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 补记 commit bab675c 的实现记录:按"第一版先做前者"落地(blocked 等人工,
    装配自愈留后续),以及中途把测试套件炸穿 75 个用例又收窄回来的完整过程——
    根因是 missingBodyDefinition 查真实文件系统,测试夹具的假 systemAgentId
    天然"缺失",改法是借用已有的 boundaryGuardApplicable 判据(只在真实执行器
    下生效),不是发明新判据。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 用户问"任务结果差是 agent 能力、架构、还是 graph workflow 问题",这份文档是
    书面复盘:按发生顺序分四类——图/模板设计缺陷(31/33 号,已修)、招聘装配可靠性
    bug(32 号已知问题的新样本)、一个复盘时新发现的架构缺口(missingBodyDefinition
    完整性闸门只在招聘路径上调用,graph-engine.js 的执行核心路径 advanceOne 一次
    都没查,本体不完整时没有第二道防线,静默拿空提示词跑真实 LLM)、agent 能力
    (不是问题,两次订正过"没工具做不到"的误判,且有正面即兴发挥的例子)。
    
    结论:主要是架构问题 + 一个具体可靠性 bug,不是模型能力问题。
    
    提出两档改进方案供讨论:
      低成本(建议直接做)——把完整性闸门接进图执行前置检查(提案 A)、
        控制台展示验收证据可见性(提案 B,纯 UI 不改行为)
      大改动(建议先讨论优先级)——标准化视觉验收工具(提案 C)、
        引擎级证据闸门(提案 D)
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • §5.1 原来断言"没有浏览器工具,物理上做不到",复盘时对照 p-bkhylu 的 org-coder
    (同样只有 bash/read_file/str_replace(+write_file),没有专门的浏览器工具)却
    真跑出了 Playwright + headless Chromium 测试,才发现这个判断错了:仓库自带
    playwright 依赖,bash 里 `node verify.mjs` 沿目录树能 require 到仓库根的
    node_modules,这条路今天的 coder/unit-tester 同样走得通。
    
    真正的差异不是工具权限,是 unit-tester 的 agent.md 从未填充过(32 号文档那类
    问题)、没有任何角色指导,而 org-coder/coder-validator 都是正常填充过的成熟
    本体。根因从"平台缺工具"改判为"这次没有指导 agent 主动想到",是一个不一样、
    也更能采取行动的结论。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 对比 e2e-demo 现有的三个项目根:
      p-v82tpc(今天的回归任务)—— 静态正则解析文本,零浏览器
      p-bkhylu("做一个 lemonai 官网")—— 真实 Playwright + headless Chromium:
        六档视口量 scrollWidth/clientWidth、getComputedStyle 量字号、手算 WCAG 对比度、
        禁 JS/reduce-motion 验证、整体挪到 /tmp 用 file:// 重开验证可移植性
      p-v1mpcl(31 号文档那条原始卡住任务)—— 无验证,任务在验收前就被取消
    
    p-bkhylu 的 DELIVERY.md 里那句"未采信自证脚本,符合 SDD §0/§2 I-4 验收独立性
    要求",搜遍 system/、docs/ 都找不到这条规则——它是那次任务的 sdd-planning 会话
    自己写进那次 SDD 的,不是仓库级别的通用约束。也就是说三条任务里,要不要认真
    验证、认不认自证脚本,完全取决于哪次任务规划时 agent 会话恰好这么想,没有系统
    保证。这就是 34 号文档 §三"影响面"判断的实锤:任务显示"已完成"与"真的达成
    原始需求"之间的落差,目前只能靠运气。
    
    34 号文档 §四 checklist 全部查完,状态行同步更新。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 之前把这条 run 手动 patch required=0 + 重试推到 completed 那次操作,其实就是
    "用真实回归任务验证 org-coder-validator 不再假阳性 blocked" 这条的证据,回来补记
    (唯一没走到的是"由 workgraph-planning 全新规划一张图"这一环,端到端证据仍缺)。
    
    复查了 validator.json 的 needs:[{kind:'artifact',required:false}]:不是同类潜伏
    问题,是刻意设计——它验的 artifact 由另一张图产出,靠任务级共享索引找,
    不依赖这条边的声明,required:false 与 33 号的 log 声明成因完全不同。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 34 号文档追加调查(§五):
    - coder-validator(预置 active 本体)的 agent.md 通篇是代码/契约正确性验证协议
      (npx vitest run + 抓假绿五件套),压根不涉及视觉/交互检查;这次任务新招的
      coder/unit-tester 两个本体 toolPolicy 都只有 bash/read_file/str_replace,
      没有浏览器/截图工具——goal-benchmark.json 的 evidence_hint 要求"打开浏览器",
      在给定工具权限下物理上做不到,不是 agent 偷懒。
    - 但也不是纯粹空手套白狼:data/companies/e2e-demo/projects/p-v82tpc/tests/
      unit-tester.check.js 是一份真实可运行的零依赖静态断言脚本,对维度 1-3 的检查
      (字号比例真解析 CSS clamp() 算出数字、三个卖点区块标题顺序、锚点跳转/平滑滚动)
      与浏览器版本基本等价甚至更精确;维度 4/5(响应式断点、资源完整性)的静态版本
      明显更弱,会放过断点内样式写错、本地资源路径错误这类情况。
    
    顺带发现:这份脚本很可能是 unit-tester 在提示词完全没有测试方法论指导的情况下
    自己想出来的——它的 agent.md 还是没填充过的 _base 原始骨架(隔壁 coder 正常填充
    过),是 32 号文档"招聘装配没填充完"那类问题的又一个真实样本(发生在方案 B
    修复提交 6a18379 落地前 1 小时,是旧行为的证据,不是新机制的回归;新机制下
    会不会正常完成,仍未验证)。32 号文档 §四追加第 6 条记录这次样本。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 用户反馈:控制台原来只能逐个节点点「输入输出」tab 看产物,缺一个全局入口。
    新增 TaskFilesPanel.vue,挂在页头,跨节点/跨 run 一次性列出这个任务的全部产物。
    
    做的时候发现分两类、且第二类之前完全没覆盖:
      · 节点产出索引(graph_files,按 company+task 检索)——规划笔记/日志/契约快照
      · 项目根(W2 ensureProjectRoot,data/companies/{cid}/projects/{pid}/)——
        真实交付物代码写的地方,跨节点共享,indexNodeOutputs 从不扫它
    
    后端补 readProjectRootRecord 导出 + GET /api/graph-runs/:id 挂 projectRoot 字段;
    项目根的文件列表复用已有的 GET /:companyId/files(此前零调用方),不新开列目录端点。
    新增 graph-run-route-io.test.js 两例(分配前 null、分配后原样透传 + 幂等)。
    
    顺带订正 34 号文档:当时断言"index.html 从未被写出来"是错的——真实网站文件
    其实在项目根里,只是没查那个目录。34 号文档 §零 记录了订正过程,问题收窄成
    "validator 有没有真的做过浏览器级检查"(仍未解决,留待下次)。
    
    全量单测 1000/1000 通过。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 真实回归任务 T-mt2r6fz0-125b 走到 completed 后回查产出,发现 org-coder-impl
    从未写出任何 HTML/CSS/JS 文件(只有 _plan.md/_research.md/coder.log),但
    org-coder-validator 给六个维度全打了 100 分。goal-benchmark.json 的
    evidence_hint 里五个维度明确要求"打开 index.html/浏览器开发者工具检查",
    这份评分显然没有真的执行过这些检查——是一次没有证据支撑的评分,不是
    "查过但判错"。
    
    不是 31/33 号修复引入的新问题,是那两次修复让这条本会一直卡死的任务真的跑到
    completed 之后,才把这个一直存在的验收缺口暴露出来。只记现象与证据,根因
    (提示词缺前置检查?validator 没有可用的浏览器/文件工具?是不是这次新招聘
    本体特有的一次性现象)留给下次调查,这次不深挖。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • org-coder-validator 在真实回归任务里被 missing_required_input 反复误判 blocked:
    executor.json/executor-fanout.json 的 test/integration→validator 边声明
    produces:["log"](required 默认 true),但 test 类节点从不写出能被 indexNodeOutputs
    认作 kind=log 的文件(coder.log 实际属于 impl,test 自己的 _plan.md/_research.md
    认不出 kind 也没有一对一无歧义可猜),这个 kind 因此永远不会被索引到,
    requiredInputsMissing 每次都判缺失——不是时序问题,是结构性、每次重试都复现的硬伤。
    
    改成 { kind: 'log', required: false },对齐 validator.json 已有的写法(它的
    needs:artifact 早就标了 required:false)。真正必需的 needs:artifact 不变,
    仍受硬闸门保护。
    
    中途走了一段弯路:最初以为该改 inboundContracts() 按 role 过滤只留 needs,
    改完单测炸了 9 个用例——大多数边只声明 produces(无配对 needs),这条链路
    正是 T-mt25ecbd 产出闸门依赖的数据源,按 role 过滤会静默削弱那次修复。
    已撤回(work-graph-db.js 这次只加注释,没有逻辑改动),细节记在 33 号文档。
    
    新增回归用例 graph-files-index.test.js ⑪:produces required:false 且该 kind
    从未被索引到时不拦下游成功,同边 needs:artifact(required:true) 依旧受保护。
    全量单测 998/998 通过。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »

  • 用真实 LLM 起了一条新任务(G-mt2r62ia-73af/T-mt2r6fz0-125b)回归验证 83afecb 的修
    复:org-planner-sdd 自判失败后沿新补的兜底边自动回退 3 次、零人工介入,最终收敛到
    completed,补上 31 号文档 §六此前用确定性测试代替的那步真实验收证据。
    
    顺带在 org-coder 子图撞见一个独立的新 bug:inboundContracts()/requiredInputsMissing()
    不按 role 过滤 graph_edge_contracts,把同一条边上声明的 produces(源节点自己产出什么)
    也当成目标节点的必需输入,导致 org-coder-validator 被 missing_required_input 反复假阳
    性 blocked(agent 自己判定 passed,引擎却强改成 fail)。已定位根因、写清复现证据与建议
    修法,记在 33-needs-gate-role-filter-bug.md,留给下次实施。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 状态行从"评估完成,未实施"改成"方案 B 已实施"。§四风险/未决问题里原来的
    4 条逐条补上实施时的实际决策:
    - SessionPool 并发复用的真实后果仍未实测,但改用了不需要知道答案的设计
      (拿锁成功才调用,从设计上不会触发这个场景)
    - 互斥锁选型定为抽共享模块(agent-session-lock.js),不新起一把
    - 失败标记定为本体目录下的哨兵文件,不碰 system_agents.status
    - 第 4 条(三处同构缺口)原样保留未决
    
    新增第 5 条:实施时发现的连带效果——hire 路由第 1 步改 await 之后,第 3 步的
    setTimeout(5000) 变成多余延迟,刻意没有顺手删掉,记录下来给以后处理。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 用户追问「这个方案能解决什么问题」,发现文档原来把这个信息拆在§三要点和§四
    风险里,没有对照着讲清楚。补一张表:撞车丢请求/卡死不可见两条真解决了,
    agent-creator 真的坏了/主动通知人/另外两处同构缺口/hire 接口异步体验这几条
    明确没解决——避免看完方案高估它的覆盖范围。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 承接 30-task-delegation-reliability-gaps §2.1(现状调研,未拍板)。评估了两条候选:
    
    方案 A(改走 POST /api/agent/task/dispatch)不成立:深挖发现它最终也是走
    selfChat() 回环 HTTP 自己,撞上 agent-creator 单会话锁时同样吃 429、同样不
    检查响应状态码——跟现在的 fire-and-forget fetch 是同一条失败路径,没有多任何
    重试保护,唯一价值是任务表里多一条可查询的行(可观测性不是可靠性),且语义
    错位(内部装配动作会被包装成用户可见的派单任务)。
    
    方案 B(company.js 直接同进程调 AgentManager.callAgent)方向对,但评估中发现
    一个原始方向没提到的真实风险:SessionPool.getOrCreate() 只判断连接在不在,
    不判断上一次调用有没有跑完——绕开 HTTP 直接并发调用会被复用到同一个还在处理
    中的会话上,两条 prompt 塞进一条 stdio 管道,行为未定义,比现在"第二个请求被
    429 丢弃"更危险。因此推荐方案明确写成「同进程调用 + 自己的互斥锁 + 有限重试 +
    失败落地为可查询状态」,不是简单的「同进程调用 + 重试」。
    
    文档状态:评估完成,未实施。互斥锁选型、失败标记落点等留给实施阶段决定。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • ## 起因
    
    e2e-demo 真实任务卡住:org-planner-sdd 自己判 input_underspecified
    并点名 org-planner-prd,但这张图里 sdd 没有任何 fail 出边——精确匹配、
    兜底边两条路都接不住,节点直接 blocked,靠人工点了「重试」才续上。
    
    ## 根因
    
    fail-fallback-edge 校验(27-P3/P4 §三.7 第五项)只在节点已经画了别的
    fail 边时才检查兜底边齐不齐。一条 fail 边都没有的节点完全不受约束——
    workgraph-planning/agent.md 原文明说这是「合法设计」。但系统里所有本体
    共用 _base 的四段式协议,VERIFY 阶段任何 agent_call 节点都可能自判
    失败,不止专职判词节点。四个骨架模板审计后发现 6 个中间节点存在同一个
    漏洞(sdd 只是撞上的那一个)。
    
    ## 决策
    
    除图的唯一入口节点外,每个节点必须留一条兜底边(判据是 forward 入度,
    不是节点名字模式)。org 层暂不动——node 全是 subgraph 类型,失败来源
    机制不同,且套用同一条规则会让三个 org 模板立刻不合法,属于 27-p3b
    「验收9」还没收口的链路,留给那边一起做。
    
    中途发现无条件收紧会炸 46 个用例/13 个文件(createWorkGraph 被大量
    测试当成建最小图的通用工具)。改法是加 strict 开关,默认关闭(行为
    不变),只在 workgraph-planning 真实提交图落库的那个唯一入口
    (createWorkGraphSafely)打开。
    
    ## 改动
    
    - work-graph-db.js / graph-engine.js:新规则 + strict 开关
    - planner.json / executor-fanout.json:补 6 条兜底边
    - workgraph-planning/agent.md:约束三等四处措辞同步
    - 新增单测:strict 模式 7 例 + 真实链路回归用例(真实引擎代码+真实
      DB+只换最外层 CLI 子进程,复现 sdd 自判失败后引擎自动路由到 prd,
      全程零 retryNode 调用)——比重跑一次真实任务更严格,可回归、进 CI
    
    978/978 单测通过。需求与决策记录见
    docs/todo/system-design/31-work-graph-fail-fallback-coverage.md。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 任务表 T10 标完成;三个阶段表(A/B/C)现在全绿;顶部版本行、开篇摘要、
    T11(没有单独立项,测试随各任务同批写掉)一并更新,别再让文档滞后于代码。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • T5 任务表行标完成,补一段实现记录(桩子设计、block_reason 列、
    resumeBillingClearedRuns、advanceBatch 的第二个排序 bug)。
    
    顺带记一笔过程:写 T5 期间发现 work-graph-db.js 被另一个会话同时编辑
    (重写 validateFailFallback),用 git diff 生成的 patch 只保留自己的 hunk
    (git apply --recount --cached)避免带上对方未完成的改动,再用一次性
    worktree 单独验证后才提交。留着这条经验:共享工作目录下 commit 前先
    git diff 走查一遍要提交的文件,别假设自己改的文件里只有自己的改动。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 自动模式的驱动原语 advanceTree 里 advanceOne 换成 advanceBatch:树上「最深
    active run」的选取逻辑不变,但推进这一步现在能一次并发 claim 一批 ready 节点,
    而不是每 tick 只推一个。核实过 advanceTree/runAuto 的返回值全仓库只被读 .ok,
    不依赖 .node/.results 的具体形状,不需要兼容层。
    
    顺带抓到并修了一个真 bug:advanceBatch 的 no-ready-node / taken-by-other 分支
    原来写的是 ok:true,跟 advanceOne 用 result() helper 的惯例(这两种情形一律
    ok:false)不一致。不修的话接进 runAuto 后,一个已经收敛的 run 会被自动循环
    一路空转到 maxSteps 才停——旧测试从没对已收敛的 run 连续调 advanceBatch,
    所以这条一直没被撞出来。
    
    新增两条测试:ok:false 语义与 advanceOne 对齐(直接绕开引擎构造边界状态);
    runAuto/advanceTree 端到端确实吃到并行(用真实 setTimeout 延迟证明并发窗口
    重叠,不是同步假象)。全量 vitest 147 文件 / 1350 用例,零回归。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • planner 骨架(brd→prd→sdd→goal-benchmark→validator)复现:三个 planning 节点
    声明了 produces 却没真落盘,executor 没抛异常就被引擎判 success;goal-benchmark
    的入边 needs:[brd,prd,sdd] 只用来拼提示词里的 ⚠️ 提示,agent 视而不见照样产出
    合法 acceptance。下游 validator 永远读不到三份文档,backward 重试撞循环硬顶后
    只能人工兜底。
    
    settleNode 判 success 之前新增两道闸门(均只对 agent_call 节点生效,subgraph/org
    节点的契约由子 work run 自己的节点过闸):
    - unsatisfiedRequiredProduces:声明的 required produces 一个候选文件都没落盘 →
      fail_reason=produces_missing,不再放行
    - requiredInputsMissing:声明的 required needs 在 graph_files 里查不到实例 →
      fail_reason=missing_required_input,不采信 agent 自报的 success
    
    两者都只判「有没有」,不判「分类对不对」——ambiguous 归类留给下游 ⚠️ 提示词处理,
    避免把「写了东西但引擎猜不出对应哪个 kind」误判成没执行。
    
    包含此前已完成但未提交的 27-P4 T3(graph_runs.max_concurrency 落库)及配套
    advance-batch 测试。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 只做了这一件事,没有跟着做「dream 改成 org/work graph 来跑」——两者被
    单独评估过:org/work graph 是单公司作用域(org graph=公司级 workflow,
    work graph=公司内某任务的节点图),dream 却是跨公司扫描,套进去要么破坏
    作用域假设要么得新开图类型;且 graph 引擎自带的验收机制(goal-contract
    benchmark/test-script)判的是「产物过没过验收脚本」,对「经验提炼得对
    不对」这种自由文本判断没有对应机制——不管套不套 graph 都得单独设计
    rubric,是同一件事。用户明确只要 REST/控制台这一半。
    
    ## REST(server/routes/dream.js,挂 /api/dream)
    
    路由本身没有新业务逻辑,全部委托给已测过的 dream-service.js:
    GET /agents(总览)、GET /agents/:id(详情,含定义文件可写性 + 经验
    审计)、POST /agents/:id/run(手动跑一次,dryRun 只看有没有新原料不
    起 LLM)、POST /sweep + GET /sweep/status(全量扫描后台跑 + 轮询,内存
    态并发锁防止连点两下)。
    
    ## 控制台(web/src/views/DreamConsole.vue,路由 /dream)
    
    一个表格 + 两个弹窗:本体列表(详情/跑一次/dry-run)+ 全量扫描按钮
    (15 秒轮询状态)。导航栏加 🌙 Dream 入口。
    
    ## 验证
    
    server/tests/unit/dream-routes.test.js 4 例,monkeypatch 掉
    dream-service 导出对象上的六个函数(不走真文件系统,不误扫真仓库
    76 个本体),只验路由层自己的逻辑:端点接线、sweep 并发锁状态机。
    
    真起服务器打了真数据:GET /agents/innovator-evolver 正确报
    SKILL.md 因没进 git 历史而不可写、经验审计吐出上次真跑沉淀的 4 条
    经验及原文;dry-run 正确报 no-new-material,没多花一次 LLM 调用。
    浏览器里走了一遍列表→详情→dry-run,与直接打 API 结果一致。
    
    955 个单测全绿。
    
    文档:29-dream-design.md §5.7 记录实现与「为什么不做 graph 化」的
    理由;28-followups.md / docs/README.md 同步更新 dream 现状。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »

  • 按任务表逐条 grep 代码,发现这份文档落后于实现相当多:
    
    · **T1 已完成**(P3C §15.5-2):SessionPool.maxSessions + scope key,两条守卫盯着。
    · **T3 后半已完成**(P3C 批 4):单 active root run 的唯一索引已 DROP,
      换成四步事务内准入(BEGIN IMMEDIATE → 重读 → 计数 → 条件更新),8 进程实测零超发。
    · **阶段 C 整个已完成,但形态换了**:产物索引做成了 graph_files **表**而不是 files.json。
      表比文件多拿到两样:部分唯一索引保证「同一路径只有一个当前版本」,
      superseded_by 让历史版本可共存。守卫 graph-files-index.test.js 七条。
    · 产物也早就按 run/node 分目录了(runs/{rootRunId}/nodes/{nodeRunId}/),
      §3.6 里「按 agent 分目录、同一 agent 不同任务混在一起」那条已不成立。
    
    §3.6 那两个 ❌ 改成校准块 —— 保留原文(它记录了当时的判断依据),
    但当前状态以校准块为准。
    
    **真正剩下的只有阶段 B**:max_concurrency 列、advanceBatch、三层额度取小、
    并行执行与部分失败降级,以及 T10 的控制台可视化。
    
    > 这是「文档落后于代码」的又一例。判断一个阶段还剩多少工作量时,
    > **先照着任务表逐条 grep 代码**,别照文档估 —— 照文档估会把已完成的三项当成待办。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • ## 决策 D:能自动查的自动查,不能自动查的把回查成本降到几秒
    
    「这条结论对不对」机器判不了,需要理解内容 —— **不假装有自动判据**。
    能自动做的只有两件,两件都做了:
    
    ① **引用真伪可以自动查**:提炼产物的 sources 必须都出自这一轮真喂进去的原料,
       编一个出处直接拒(前置闸门,连去敏判定都不用调)。
       编了出处的经验是「无法验证」最危险的形态 —— 人抽查时顺着一个不存在的指针放弃,
       然后**默认它是真的**。
    ② **auditDistilled()**:把每条结论与它引用的原料原文并排列出来,
       指针悬空标 null(原料被清理过 / 出处是编的)。
    
    真跑那 4 条实测:**8 条引用全部取得回原文**,模型没编出处。
    ⚠️ auditDistilled 的输出**不是质量分**,别当成那个用。
    
    ## 任务态清理(28 §5.6)
    
    四道判据全过才删:① 公司在 company_agents 名册里;② 目录名在**任务态白名单**里;
    ③ mtime 早于 N 天(默认 14);④ run_* 对应的 run 已到终态。默认 dry-run。
    
    **第 ② 条是踩出来的**:第一版写成黑名单(「不在保护名单里的都算任务态」),
    dry-run 直接选中了 trend-scout-global/idearun/venv 和 youtube-crawler/idearun/data
    —— 一个 Python 虚拟环境、一个数据目录,都在**真公司**底下,都不是任务态。
    **删错不可逆,留着最多占磁盘 —— 判据必须是「认得出才删」,不是「不认识就删」。**
    
    读不到名册时一家公司都不认(fail-closed),守卫里单独钉了这条。
    公司态(memory/ conversations/)永远走「不许清」那条分支 —— 那是 dream 的唯一原料,
    删掉不可再生(28 §5.6b)。
    
    实跑 30 天窗口:待删 0,跳过 955(556 还新 / 74 不在名册 / 60 公司态 / 11 白名单外)。
    
    全量:145 文件 / 1338 测试全绿。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • ## 前置:存量记忆的搬家(19 文件 / 269 行)
    
    写入侧上一轮改了,但**存量不会自己搬家**。实查现有 `## 关键事实` 里
    **没有一条真事实** —— 全是重复心跳行、工具调用 id、和以 `...` 开头的半句。
    而 memory.md 会被注入**每一轮**提示词,这些东西一直在冒充事实。
    
    scripts/migrate-memory-raw-section.js 把它们搬进「原始记录(未提炼)」。
    先 dry-run 再 --apply,改前逐个 .bak(这些是 gitignore 的运行态,没有 git 历史兜底)。
    
    判据刻意窄:只搬 `- [YYYY-MM-DD] … → …` 这一种形状(旧自动追加的唯一形状)。
    **搬错比留错更坏** —— 留下最多多一条噪声,搬错是把人写的东西降级成日志。
    
    ## 真跑:innovator-evolver,40 条原料
    
        { "distilled": 4, "accepted": 4, "rejected": [] }   耗时 114s
    
    四条产出都做到了抽象:yt-dlp / Invidious → 「本地下载工具 → 备用镜像源」;
    scorer.js / SKILL_v1.md / system/templates/... 一个都没出现。
    
    **顺着 sources 抽查过**(可追溯的第一次实际用途):4 条引用全部对得上原料。
    「按关键词覆盖率打分会被刷到虚高分」那条引了 #21/#22/#27/#28,而 #27 原文正是
    「从零重写,采用 expected_output 逐 case rubric + dimCeil 上限机制,杜绝 coverage-based」。
    **它是跨 4 条记录归纳出来的**,不是逐条改写 —— 正是「一次调用吃掉全部原料」
    那个选择要换来的东西。
    
    ## 闸门单独验过:零拒绝 ≠ 闸门有效
    
    真跑里 4 条全过,说明去敏闸门**一次都没触发**。所以单独喂了三条给 dream-screener 真跑:
    · 含公司名+域名+绝对路径 → false,理由点名「域名 lemonai.ai 和绝对路径 /Users/…」
    · 心跳日志原文摘录 → false,理由点名「原文搬运」「工具调用 ID 可关联到具体运行实例」
    · 干净的抽象经验 → true
    
    三条判据都按 agent.md 写的那样生效,**且拒绝理由都点到了具体是哪几个字** ——
    那是 agent.md 里明确要求的。
    
    ## 空转保护实跑
    
    第二次调用(原料没变):{"skipped":"no-new-material"},一次 agent 调用都没起。
    
    ## 还没做的
    
    定时挂载(决策 C)、写定义文件(SKILL.md / soul.md / agent.md)、
    决策 D(质量怎么评 —— §5.5 那次抽查是**人工**顺着 sources 回查的,不是自动的)。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • ## 两个本体(都过得了毕业闸门)
    
    · dream-distiller —— 把一批原始记录提炼成可复用经验,交 ```json 数组
      {title, body, sources};没有值得留的就交 []。
    · dream-screener —— 逐条判「这条能不能给别家公司看」,交 {shareable, reason}。
    
    **决策 A 的独立性写在两处,缺一不可**:
    · 代码层:判定**一条一次调用**,提示词里只放 title + body,**不放原料**;
    · 本体层:dream-screener/agent.md 明写「你看不到原料,也看不到是哪家公司
      —— 这是故意的」。守卫里有一条专门断言这句话在 —— 否则下一个人会顺手把原料
      塞进提示词「让它判得更准」,而那恰好把独立性拆掉了。
    
    soul.md 也承担判据的一半:screener 的人格写的是「你是一道闸门,不是审稿人。
    审稿人的本能是帮它改好,闸门的本能是不确定就不放」。
    
    ## 两处失效方向都是硬的
    
    · 提炼取不出 JSON → **抛**,不是静默返回空。「产出格式坏了」和「没提炼出东西」
      是两件事,混为一谈会让前者以后者的形式永远藏下去 ——
      每天显示「今天没经验可沉淀」,而真相是解析一直在失败。
    · 判定解析不了 / shareable 不是布尔(比如给了字符串 "true")→ 判否,
      并把原文片段带进 reason,让人看得出是「判否」还是「判炸」。
    
    ## 纠了自己两次
    
    ① 测试第一版把解析与失效分支**在测试里重抄了一遍**再断言 —— 那是在验一份复制品,
       代码改了它照样绿。改成加一条 setDreamAgentCaller 缝,只换掉「真起 CLI」那一层,
       解析、判空、失效方向全走真代码。
    ② agent.md 的相对引用按 **cwd 深度 3**({aid}/{cid}/{taskId}/)解析,不是按文件
       自身位置 —— 仓库根是 ../../../../../。我按文件位置写了 ../../../,
       agent-md-refs.test.js 当场判红。**守卫替我抓的,不是我自己发现的。**
    
    ## 还没做的,写进文档 §5.4(别当成 dream 上线了)
    
    · 定时挂载没做(决策 C 说每日一次):现在只有 dreamOnce(agentId) 这个可调用单元,
      没挂调度、没 REST 入口。
    · 还没写定义文件:只写本体根的 memory/experience.md(纯经验积累,删掉无副作用)。
      三个 git 跟踪的定义留给下一步,闸门与 definitionWritability() 已就位,
      缺的是「往里写什么、写成什么形状」那半边设计。
    · **没有一次真 CLI 验收**:CI 里换掉的是 callDreamAgent 那一层,验的是解析与失效方向,
      不是模型写得好不好。两个本体的提示词**至今没有被任何模型读过** ——
      这正是 P3B W4 记过的形态(mock 从不读提示词)。
    · 决策 D(提炼质量怎么评)仍未定;可追溯是它的便宜起步,不是替代品。
    
    全量:144 文件 / 1323 测试全绿。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • ## 步骤 2:「有哪些公司」只认 company_agents 表
    
    system/agents/{aid}/{cid}/ 是**约定不是校验**。实查 96 个二级目录里混着
    train/ workspace/ 和带时间戳的测试残留(tmp-w7-*-1786986291739-*)。
    拿目录枚举公司 = 把测试夹具当经验原料喂给提炼 agent。
    
    改成查表,另补保留段 _global(全局 agent 的运行态落点,没人「雇」它所以不在表里)。
    **目录从此只用来定位文件,不用来枚举公司。**
    守卫里真造了 train/ 和 tmp-w7-* 两个目录,断言它们不进原料。
    
    ## 空转保护:水位线按「条数」不按 mtime
    
    实查 75 份 memory.md 只有 7 份有非模板内容 —— 每日跑起来绝大多数 agent 没有新原料。
    不拦的话每天几十次「读完发现没东西」的 LLM 调用在烧钱。
    
    **判据用条数而不是 mtime**:mtime 会被任何一次无关写入推动(例如别处重写整份
    memory.md),条数只在真的多出记录时增长。用 mtime 的话,空转保护会在
    「文件被碰过但内容没变」时失效。
    
    ## 决策 A 的失效方向写进代码
    
    去敏判定 agent **抛异常也算拒绝**,并把「为什么」写进 rejected[]。
    否则现场只看到「少了一条」,查不出是判否还是判炸。
    「少沉淀一条经验」与「泄漏一次机密」代价不对称,判据必须偏向贵的那一侧。
    
    ## 步骤 5:可追溯
    
    每条原料带 source({公司}:memory.md#{行号}),提炼产物落盘时把 sources
    写进 experience.md 的引用行。没有它,dream 的产出无法验证对错 ——
    与 FDE 那边「LLM 自己汇报分数」是同一个问题。
    
    ## 步骤 3 还差什么(写在文档 §5.3,别当成做完了)
    
    编排 / 空转 / 闸门 / 落盘 / 可追溯都跑通了(6 例守卫),
    **缺两次真 agent 调用的默认实现**:提炼 agent 与去敏判定 agent 的本体还不存在。
    默认实现现在是一句显式 throw(「尚未接线」)而**不是静默返回空** ——
    静默返回空会让调用方以为「跑了但没提炼出东西」,那是本仓库反复出现的失效形态。
    
    也还没写定义文件:writeDistilled 目前只写本体根的 memory/experience.md
    (纯经验积累,删掉无副作用)。三个 git 跟踪的定义留给下一步,
    definitionWritability() 已能报出「现在能不能写、不能写是为什么」。
    
    全量:144 文件 / 1316 测试全绿。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 29-DREAM §四 的五步里先落两步。
    
    ## 步骤 4:本体定义文件的 git 历史闸门(决策 B.3)
    
    用户定案:soul.md / agent.md **直接落盘**,但写之前必须确认这份文件已经在
    git 历史里 —— 别导致直接修改而没有历史。
    
    definition-write-gate.js 两条判据都满足才放行:
    ① 文件被 git 跟踪;② 该文件没有未提交改动。
    判不出来(不在仓库 / git 不可用)一律拒绝 —— fail-closed。
    
    **为什么是「拒绝并报告」而不是「脏就先替它提交一把」**:后者看着更顺手,
    但那正是本仓库记过的一类事故 —— 多会话共用同一个 worktree(27-P3C §15.4)。
    一份未提交的改动很可能是**另一个会话正在写的东西**,替它提交等于把别人的
    半成品写进 main 且署错名。把「要不要提交」留给人。
    
    守卫 5 例,含「拒绝时必须给出下一步」那条 —— 撞上闸门的人(或 agent)
    要能照着做,否则只能猜。
    
    ## 步骤 1:memory.md 的自动写入不再冒充「关键事实」
    
    原实现取任务与结果的第一行、砍到 80/100 字符,写进 `## 关键事实`。
    那不是提炼,是搬运 + 截断。实测产物(cto/_global/memory/memory.md):
    
        - [2026-08-20] [SYSTEM HEARTBEAT] → 🔧 [TOOL_CALL] Bash (ID: toolu_01RsQ3gh...)
    
    **工具调用 id 被当成了「关键事实」**,而 memory.md 会被注入每一轮提示词。
    28 §5.6b 点名的错误版本是「自动把原文写进共享 SKILL.md」——
    这套已经是那个错误的单公司版,只是还没跨公司共享所以还没造成泄漏。
    
    改法:
    · 换段 —— 自动写入落到「原始记录(未提炼)」,`## 关键事实` 只由提炼产物填。
      读的人和 agent 一眼分得清「日志」和「结论」;这一段同时是 dream 的输入面。
    · 滤掉确定的噪声(工具调用标记 / 空结果 / 只有心跳标记的任务),
      但**不猜「哪条重要」**——猜重要性需要理解内容,那是 dream 的活,
      在这里做等于把提炼下放到一个正则里。
    · 不再截成半句:上限放宽到 200 并取完整第一行。截断残渣读起来像事实、
      其实缺主语,比不留更坏。
    
    ⚠️ 踩到一条:噪声判据初版有「任务与结果都短于 8 个字符就丢」。那是按英文长度
    想出来的阈值 —— 中文 8 个字是一句完整的话,实测「结果甲甲甲甲甲」(7 字)
    整条被丢。已删该规则。**凡是拿长度当信息量代理的判据,先问一句这是按哪种文字算的。**
    
    全量:143 文件 / 1310 测试全绿。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 28-followups §1.1 一直是「方向已定、设计未定」。这份把取舍摆出来并记下拍板结果。
    
    ## 先看清原料:它现在是脏的(全部实查,不是推测)
    
    · **写进 memory 的不是「事实」,是截断的日志行**。appendToMemoryMd 的全部逻辑是
      「取第一行、砍到 80/100 字符」。cto/_global 的实际内容里,三条「关键事实」是
      `🔧 [TOOL_CALL] Bash (ID: toolu_01RsQ...)` —— 工具调用 id。
      §5.6b 点名的错误版本是「自动把原文写进共享 SKILL.md」;**现在这套已经是那个错误的
      单公司版**,只是还没跨公司共享,所以还没造成泄漏。
    · 长期记忆是一个 3000 字符的滚动窗口,没有按重要性保留的机制。
    · 96 个「公司态目录」里混着 train/ workspace/ 和**带时间戳的测试残留**
      (tmp-w7-*-1786986291739-*、qroute-co-13/14)。dream 第一步「枚举所有公司」
      现在没有可靠答案 —— 可靠的答案在 company_agents 表里,目录只能用来定位文件。
    · 75 份 memory.md 里只有 7 份有非模板内容。**dream 现在几乎没有原料。**
    
    ## 四条拍板(2026-08-20)
    
    A 去敏 = 独立判定 agent + 写作要求。失效方向是「少沉淀」不是「泄漏」——
      两种错代价不对称时判据偏向贵的那侧,与 P3B §八 FAILING_VERDICTS 同一条经验。
    B 落点 = memory/ 与 SKILL.md 都写,**必要时迭代 soul.md / agent.md**。
    C 触发 = 定时每日一次。
    D 顺序 = 上游修复与 dream 一起做。
    
    ## B 把范围扩大了,随之而来的约束单列一节
    
    「本体只有一份」意味着写 agent.md / soul.md 影响**所有雇了它的公司**,
    而不是提炼出这条经验的那一家。所以四个落点按可逆性分层,并记了四条硬约束:
    · agent.md 有一处 2000 字符截断 —— **作用点要说准**:那是给规划 agent 看的
      「角色定义摘录」(graph-engine.js:915),agent 自己那条装配链不截断。
      判据因此是「保证前 2000 字符仍然自足」,不是「不许追加」。
      (初稿我按记忆写成「装配时只读前 2000 字」,查了代码才改对。)
    · 这四个里三个是 git 跟踪的**定义**,不是运行态 —— dream 改它们会进 git status。
    · 毕业闸门读这些文件,写坏会让本体雇不进任何公司。
    · 必须能分别回滚:经验写坏只影响上下文,agent.md 写坏影响所有公司。
    
    ## 还没定的
    
    决策 D(提炼质量怎么评);B.2 里「定义文件直接写还是走提案」——
    我建议走提案并写进了推进步骤,但那是建议不是拍板。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • ## 病症(真跑实测)
    
    2026-08-20 那条 run 的 timeline 里,**每个节点**的产物索引写入都失败:
    
        node.output | 产物索引写入失败 contract.json: UNIQUE constraint failed: index 'idx_graph_files_path'
        node.output | 产物索引写入失败 sdd.md:       UNIQUE constraint failed: index 'idx_graph_files_path'
    
    19 次 agent 调用、每次两三个文件,无一成功。
    
    ## 根因:加了新索引、没删旧索引
    
    产物索引加「版本」之前,唯一索引是无条件的
    `UNIQUE(company_id, COALESCE(task_id,''), rel_path)`。加版本之后建表块换成了
    带谓词的 idx_graph_files_current(WHERE superseded_by IS NULL),**但没人删旧的那条** ——
    `CREATE ... IF NOT EXISTS` 只管不重复建,不会删已有的。
    
    于是 recordFile 那套「先把旧行 superseded_by 指向新行、再插新行」的版本化写法
    在存量库上整个失效:旧索引不认 superseded_by,同路径第二行直接撞。
    而重试恰恰会让同一条 rel_path 被产出第二次。
    
    ## 失效方向:静默
    
    writeFileIndex 把 recordFile 的抛降级成一条 timeline,**节点照样 success**。
    后果是产物索引在任何有重试的 run 上都不全 —— 而下游节点正是靠这份索引
    按 kind 找上游产物。不报错、不影响测试、git status 干净。
    
    ## 为什么没有任何测试照到
    
    新建库压根没有那条索引(建表块里早就只剩 current 那条),**只有存量库会踩**。
    
    这是同一类问题的**第三次**(tasks 加列的索引顺序、墙钟锚点迁移、这次)。
    判据固定成一句话:**凡是碰 schema,「存量库重启」那条路必须单独走一遍。**
    
    ## 修 + 验
    
    迁移里一句 DROP INDEX IF EXISTS idx_graph_files_path。
    守卫 graph-files-stale-index.test.js 走存量库重启那条路,并验版本化语义没被削弱
    (同路径两行、当前版本恰好一条、旧行指向新行)。反向验过:不删就红。
    
    生产库已实跑验证:删索引后同路径连产两次不再抛,graph_files 24 行未受影响
    (备份 /tmp/graph.sqlite.pre-idxdrop)。
    
    全量:141 文件 / 1300 测试全绿。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 28-followups §3.1。**审计结论与那条待办原来的写法不一样,两列要分开处理。**
    
    ## source_kind:删
    
    与 origin 一一映射(global_agent↔builtin / company_hired↔created),
    实查生产库 76 行零例外。全仓唯一读侧是 migrate() 里那条 origin 回填,
    而那是给「origin 列出现之前写下的行」用的一次性迁移。
    
    顺序:**先回填、再删列**,两步都用 hasColumn 守着(幂等)。反过来做不报错 ——
    库能开、测试能过,只是那几行 origin 悄悄是错的。守卫
    source-kind-drop-migration.test.js 走存量库重启那条路,专门钉这个顺序,
    反向验过:弄反立刻红。
    
    写侧散在 3 处生产 INSERT + 35 个测试文件。批量改的时候正则误伤了 4 处
    (吃掉了 JS 默认参数、位置占位符、ON CONFLICT 的赋值行),逐个修回并复查了 diff ——
    **这种跨几十个文件的机械改动,靠「全量跑一遍」兜底比靠正则写得对更可靠**。
    
    ## legacy_path:不能删,它还没死
    
    原待办说「所有读取点都已改成从 id 推导」——那半句对新行成立,对存量行不成立:
    · 新行 legacy_path 恒等于 system/agents/{id}(确实冗余);
    · **存量行里存着批次 4 之前的公司侧路径**,而 graph-seed-service 判「悬空行 / 孤儿行」
      靠的正是这个路径指向的目录还在不在。从 id 推导出来的路径永远指向 system/agents/,
      那条判据会整个失效。
    
    实查生产库:76 行里还有 2 行是老路径(org-planner / org-coder 指着已不存在的
    data/companies/mycompany/agents/)—— 正是这条判据要认出来的那种行。
    
    退出条件写进了 graph-db.js 的建表注释(不只留在文档里):
    库里不再有 legacy_path <> 'system/agents/' || id 的行。
    
    ## 顺带记一条:getDb() 会就地迁移生产库
    
    删列那次,生产库的列是被一条**查状态用的**一行 node -e 删掉的 ——
    服务当时没重启,人也没打算迁移。结果是对的(幂等;与备份逐行核对 76 行一致、
    origin 全部按映射回填正确),但「读一下状态」不该顺手改 schema 这件事值得知道。
    闸门只挡测试进程,故意不挡普通脚本(挡了服务自己也起不来)。
    注释里给了只读的正确姿势。
    
    全量:140 文件 / 1299 测试全绿。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • ## 验收 4:从「静态成立」变成真的跑过一次
    
    原状态是 🟡「静态成立,未真跑」—— 人读代码把
    fixture verdict → FAILING_VERDICTS → readNodeProduct → callAgentNode 判 fail
    这条链读通了,但没有任何一次真跑或真链路证据。
    
    现在 graph-real-chain-smoke ⑥ 走完整条:fixture 产出 verdict="attributed"
    → 节点 fail、fail_reason=input_underspecified、沿 fail 边点亮下游、
    判词落在**下游节点**行上(判词的载体是「点亮它的那次状态转换」,不是失败节点自己)。
    反向验过:verdict 改成 passed 立刻红。
    
    写 fixture 时踩到一条值得记的:fail_reason 是封闭域 ATTRIBUTION_REASONS,
    第一版编了个 contract_invalid,被**按设计降级成 null** 并留一条 timeline ——
    引擎不认识的归因一律不信。判据没错,是 fixture 错。
    
    ## 验收 2 / 8:由 2026-08-20 那次真跑验掉(§六ter)
    
    · 2 —— 19 次真 agent 调用之后 `git status --porcelain` 完全为空,交付物都在项目根内。
      这正是 §六bis「后半被并行 agent 打破」那条的干净环境重验。
    · 8 —— 判据取「它引用了只可能来自提示词的内部 id」:triager 判词原文写着
      「org-coder-impl 私有目录 rn_96a8cd696dcc 下只有 _research.md」,
      rn_96a8cd696dcc 是 graph_run_nodes.id,agent 没有别的途径知道它。
    
    ## 验收 9:产出端通了,消费端没等到那个形状
    
    真跑里 triager **确实产出了两半地址**(orgNode + workNode)——
    这一条本身有分量:27-P3/P4 §八.22 第 13 处记的正是「引擎四环全通,
    但产出方 agent.md 里根本没有这个键」,那半条现在通了。
    
    紧接着「忽略跨层地址」那条**不是缺陷,是判据在正常工作**:这次回退发生在
    work 层内部,edge.to 本身就是 agent_call 节点,已是最细粒度,没有跨层可言。
    缺的是**那个形状**:一次 org 层回退边、且目标是 subgraph 节点。
    
    别把「机制没验」和「机制没有」混为一谈 —— 定点重置的逻辑侧有
    graph-cross-layer-address.test.js 三例注入式覆盖,缺的只是真跑里发生过一次。
    
    ## 顺带
    
    · template-verdicts 的样本非空那条补 ENOENT 容忍。它扫**活目录**,
      而 graph-real-chain-smoke 会在 system/agents/{aid}/{cid}/ 下建了又清运行态 ——
      文件在「列出名字」和「读它」之间消失是正常的。walk() 与 violations() 早就容忍了,
      只有这一处漏了,实测偶发红过一次。**扫活目录的守卫,每一处读都要容忍 ENOENT。**
    · 真跑 timeline 里发现一条未修的:每个节点的产物索引写入都撞
      UNIQUE idx_graph_files_path 失败并被降级成日志(重试时同路径再写一次)。
      后果是 files.json 产物索引在有重试的 run 上静默不全 —— 归 P4 一起处理,记在 §六ter。
    
    全量:139 文件 / 1297 测试全绿。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • agent_call 与 subgraph 是**两段不同的默认实现**(defaultAgentExecutor /
    defaultPlanWorkGraph),各有各的 onAcpEvent 累加、各有各的守卫开关分支。
    上一轮只覆盖了前者,「规划子图」那半条链仍然是零真实覆盖。
    
    现在走完:defaultPlanWorkGraph → AgentManager → ClaudeCliProtocol(mock)
    → extractPlannedGraph 解析回复 → createWorkGraphSafely → 建子 run。
    
    断言两处假 planner 天然绕开的接线:
    · 子 run 的定义确实来自 fixture 那张图(节点名 / systemAgentId 逐个对)
    · 规划那一轮烧的 token 也进了预算 —— 走的是 defaultPlanWorkGraph 自己那条
      onAcpEvent,与 agent_call 那条不是同一段代码
    ③ 的守卫断言补上 subgraph 分支的正反对照。
    
    新增 fixture workgraph-planning.json:图 JSON 同时放进 chunks 与 result
    (mock 下 output 取哪一半由 AgentManager 决定,不该由 fixture 来赌)。
    
    反向验过:抽掉 fixture 里的图 JSON、或把它的 usage 归零,对应用例分别变红。
    
    **覆盖边界写在用例注释里**:跳过 resolvePlanningAgentName 里的按需 hire
    (预塞一行 company_agents)—— hire 要一条真实公司记录,那条路径另有
    company-hire-org-layer.test.js 盯着;这条 smoke 验的是规划链路,不是招聘。
    
    全量:139 文件 / 1296 测试全绿。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • ## 一、W7「零边图」不是待办 —— 它早修了,是注释在骗人
    
    `company-service.js` 的判据注释仍写着「判据用**有没有边**」,并留着一段
    「已知残留:单 org node 的最小图没有边,判据③不生效……真跑到那一步再看」。
    
    **那个残留在 `58a2865`(08-17)就修掉了**:`orgGraphMembership` 现在的主判据是
    `authored_by='planner'` 的节点存在(「orggraph-planning 提交过一张图」的直接证据,
    零边也认),边数降为存量行的回落判据;守卫 `company-hire-org-layer.test.js` 的
    `CO_ZEROEDGE` + `W7-fix` 两条盯着。
    
    注释没跟着改,于是它把读的人**引向一个已经修好的缺陷**去重修一遍 —— 我就是这么被
    带偏的:读到那段注释就没再往 `orgGraphMembership` 里跟,还据此往待办清单里写了一条。
    这是「指路牌失效」那一族,和 CLAUDE.md 死链同型,只是方向相反(那边指向不存在的东西,
    这边描述已不存在的洞)。
    
    判据的措辞也改了:**「成型」的判据在 graph-service.orgGraphMembership(),不在这里**,
    免得下一个人照注释理解。P3B 文档与 docs/README.md 的对应条目一并更正。
    
    ## 二、还上「真实路径 smoke 进 CI」那笔欠账的一半(27-P3/P4 §十 硬规矩 2)
    
    原话是「凡是靠注入点验的能力,都要有一条真实路径的 smoke 进 CI 才算验收完成 ——
    这条欠账仍未还」。此前唯一走真实路径的 `scripts/real-pm-smoke.js` 要真 API 额度、
    人工跑、而且验的是 DevLoop 不是图执行。
    
    做法是把「真 LLM」和「真代码路径」拆开:**只把最外层的 CLI 子进程换成 fixture 回放**,
    setAgentExecutor / setPlanWorkGraph 一个都不调。链路完整走
    advanceOne → defaultAgentExecutor → AgentManager → ClaudeCliProtocol
    → onAcpEvent → 落盘 → readNodeProduct → settleNode → spendBudget → 边界守卫。
    
    三条断言各盯一处**假 executor 天然绕开**的接线:
    · ① mock/files 真的落到节点产物目录(假 executor 直接 return,这一环整个不存在)
    · ② token 用量真的从 session/result.usage 数进预算 —— **就是 §六 验收 10 卡了两轮的那一维**
    · ③ boundaryGuardApplicable 在这条路径上为真(注入假 executor 时它恒为假,
         那条唯一有实际后果的分支实际零覆盖);带反向对照,注入后必须变假
    
    反向验过:断掉①的落盘、断掉②的累加,对应用例分别变红。
    
    为此改了一处 mock:session/result 的 usage 原来硬编码 {input:0,output:0},
    现在 fixture 可指定(缺省仍是 0,既有 fixture 行为一个字不变)。
    **不改这一处,token 那一维在 CI 里永远产不出数** —— 验收 10 当初就是卡在这儿。
    
    **没还清的部分写在文档里,别当成还清了**:真 LLM 仍进不了 CI;
    subgraph 那一支(defaultPlanWorkGraph)仍只有注入式覆盖;
    多节点 / 回退边 / 熔断没进这条 smoke,它只推一个节点。
    
    afterAll 清掉真实链路建出的公司态目录(gitignore 挡着不进库,但留着会让别的
    用例遍历 system/agents/ 时多扫一份)。
    
    全量:139 文件 / 1295 测试全绿。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • ## 移进 done/
    
    · 27-p3c-goal-task-model.md —— 五批实施完毕,§15.5 / §16.8 的后续项也全部收掉。
      新增 **§十七**:欠账清单对账、边界守卫从「乱扣帽子」改成「留证据不判罚」、
      测试污染生产图库(第四次踩同一族,但换了个方向进来)、那条卡了两天的 run,
      以及 **§17.5 真跑验收** —— org-planner-sdd/benchmark/validator 全 success、
      work run completed、父节点自动拉回、org-coder 起实现层子图、
      org-coder-validator 判 fail 走回退边打回 impl(loopCount 1)。
      **返工闭环第一次由真 agent(不是注入的假 executor)走通。**
    
    · 27-p3c-batch3-handover.md —— 四条复核结论全修完、§五 那条 run 已解开,
      §七 待办全部打勾。从待办转为**事故记录归档**:§六 那几条多会话协作规则是真踩出来的。
    
    两份的相对链接都已重指(done/ ↔ todo/ 跨目录),no-dead-path-references 守卫通过。
    
    ## 留在 todo/ 的,状态说清楚
    
    · 27-graph-agent-architecture.md —— 状态行校准。那一行是别人判断「能不能搬 done」的依据。
    · 27-p3b-real-run-runway.md —— 加状态行:验收 7 ⛔ 真跑不成立(readme-writer 混进
      org graph,**未修**)、2/4/8/9 未在干净环境验。缺陷② 的**根因**今天修了,
      但特意写明「**根因修了不等于验收点验了**」—— 不然下一个人会照着状态行当成验过。
    · 27-p3-p4-work-graph-console.md —— 在索引里写明留 todo 的原因:
      §十 那笔「真实路径 smoke 进 CI」的欠账未还。
    · 28-followups.md —— §3.3 标已修(含「GET /info 的 404 闸门仍没修,别当成修过」);
      §五 守卫表加两行(graph-db-prod-guard / heartbeat-company-scoped),
      并补第七条的来历。
    
    ## docs/README.md
    
    索引补上新增的 done 条目与 P3B / 28-followups 行,主线说明改成
    「当前未完成的是哪几件」——原来只说完成了什么,读的人得自己推。
    
    全量:138 文件 / 1292 测试全绿。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 记三件这一批换来的东西:
    
    §16.5 第 3 步怎么做到不碰契约:dispatch 的九步副作用里只有第 ⑧ 步是存储,
    把 saveTaskMeta/loadTaskMeta 变成表的适配器、其余八步一行不动,URL 与请求体
    形态天然不可能变。字段落点的三个判断也记了(objectiveId 可推导所以不存、
    sourceConvId 零读取方所以删、没选 JSON blob 因为 R-19.2 否过那个形态)。
    
    §16.6 删掉的是「猜」不是「记录」:122 行的三策略启发式换成 parent_task_id
    显式记录;getTaskTimeline 保留,树从表来、正文仍读 agent 的一手会话记录。
    
    §16.7 两次「测试全绿 ≠ 没坏」:routes/tasks.js 漏改(没有测试走那条路)、
    控制台栏宽(构建/单测/探针都不会报)。与 §16.2 那个「存量库一启动就炸」
    (测试能覆盖但没人写)合起来是一条经验 —— 新建库的路径、纯逻辑的路径由单测
    天然覆盖;「存量数据」「真实接口」「肉眼可见」这三类必须另外安排人走一遍。
    
    §16.8 留了三条:tasklog 目录改名待做、tools-base.md 的端口仍是 3000(实际
    3010,已真咬过人)、TaskTimeline.vue 的两处字段语义变了。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 记两条这一批换来的东西:
    
    1. 加列时把 CREATE INDEX 写进建表块,会让**所有存量库一启动就炸** ——
       建表块先于迁移块执行,存量库上 CREATE TABLE IF NOT EXISTS 是 no-op,
       索引引用的那一列还不存在。而新建库(单测默认路径)完全正常。
       由此得到一条可复用的规矩:凡是加列,必须同时测「存量库重启」那条路 ——
       新建库的路径由每个单测天然覆盖,存量库那条没人走,而生产上只有存量库。
    
    2. 回填沿用原 taskId 而不是新发:conversations/task-{taskId} 是目录名、
       汇报链路按它查找、summary 里互相引用。换 id 等于把引用全断掉,
       而回填的目的恰恰是别让历史消失。
    
    并记下第 3 步动手前的前提:/task/dispatch 的 URL 与请求体印在
    tools-base.md 里(所有 agent 的工具说明),一个字不能改;而 agent-chat.js
    在 8-19 被另一个会话大改过,预研写在那之前,所以要重新读现状再动手。
    
    顺带记一处过期且已咬过人的:tools-base.md 印的是 localhost:3000,
    实际端口是 3010 —— 回填出来的派单正文里有人手写「端口 3010,不是 3000」
    在纠正它。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »

  • ## 批 4:解除「一家公司同时只有一个 active root run」
    - DROP idx_graph_runs_one_active_root(建表块删掉 + 迁移块显式 DROP,
      CREATE ... IF NOT EXISTS 对存量库不生效)
    - max_parallel_tasks 从 company.json 调用时读(不是模块加载时快照,
      否则改配置要重启才生效且不报错);缺省 1、非法回落 1 并留声、硬上限 20
    - 准入判据「从活跃集外进入活跃集」按额度计数
    
    **生死线用 8 个真进程并发抢坑实测**(不是纸面论证):max=1/2/3/5 四组,
    每组恰好抢到 max 个、库里活跃数 = max,落选进程各吃 40 次 RunSlotBusyError,
    零 other 错误。唯一索引没了之后,准入事务是真守卫。
    
    ## 批 3 对抗复核的四条遗留
    - N1 🔴 cancelQueuedRun 的前提被批 3 自己的 requeueBlockedRootRun 改没了:
      queued 的 run 现在可以是跑过一半的。探针实测取消后子 run 残留
      paused/stop_requested=0 —— 那条 running 的子 run 继续调 agent 烧 token。
      改为无条件走 engine.stopRun
    - L1 ⚠️ 恢复路径对 manual 只兑现一半:注释写着「T1 永远回不来这个后果因此
      消失」,但调度器故意不碰 manual → 退回队列后没人接。定案:「manual 不自动
      出队」约束的是首次起跑的授权,已被人亲手起过的不算新授权。
      判据用 attempt>0 而不是 started_at —— 后者会被 requeue 清成 NULL,
      恰好在需要它的那一刻是空的(实测踩过)
    - N2 🟠「退回队列」对用户完全不可见:200 + ok:true + 按钮全灰 + 图消失 +
      一句「节点状态一律 pending」的假提示。加 notice 明说
    - N3 🟠 isSlotRaceError 把 InvalidTransitionError 当竞态吞掉,而探针证伪了
      那条注释:被推走时条件更新返回 0 不抛,真正抛它的只有「调用方声明了非法
      转换」。删掉该分支,让它吵起来
    
    四条里三条是同一个模式:注释承诺的前提被本轮自己的改动改没了,注释还留着。
    文档 §十三.3 / §十四.4 已就这个模式立过两次案,这是第三、四、五次。
    
    ## 文档
    §十五 实施记录,含 §15.4 一次流程事故:87b776c 由第三方会话在对抗复核完成
    前误提,提交说明的「1201 用例全绿」压在一份尚未通过复核的代码上。
    
    全量:128 文件 / 1240 测试全绿,web:build 通过。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 起因是「全量测试偶发挂一条」。查下来既不是回归、也不是那 45 个孤儿进程(它们 CPU 早归零、
    不再写任何东西),而是**还活着的心跳在测试扫描 system/agents/ 的同时往里建目录**:
    
        locator.taskDir() 的落点是 system/agents/<agent>/<companyId>/<taskId>,
        运行态目录落在本体目录里属既定设计;但心跳每 5 分钟建一个新的
        (cto/_global/ 已 263 个子项且在涨),于是扫描 system/agents/ 的守卫测试
        (no-dead-path-references 那一类)会撞上瞬时竞态:列到了目录名,进去时那一层还没写完。
    
    症状是偶发假失败、重跑就好 —— 这类最费人,因为第一反应总是去怀疑自己刚改的代码。
    
    改法:server/index.js 启动的那个 setTimeout 块里,恰好装着全部「会自己起 agent 的东西」
    (两处中断恢复 + 任务队列扫描 + 两路心跳),所以一条早退就够,不必在五个地方各加一个判断。
    
        DISABLE_BACKGROUND_AGENTS=1 bash start.sh
    
    实测:127 文件 / 1226 用例全绿,跑前跑后 cto/_global 子项数都是 263。
    
    **验证它生效不能只看日志里的 ⏸** —— 那只证明代码走到了早退。硬判据是目录数前后相等,
    也就是真的没有东西在写。文档 §七 把这条写成了可粘的三行。
    
    排掉的两个坑,都记在文档和 .env.example 里:
    
    1. `.env` 里不能给这个键赋空值。start.sh 是 `set -a; source .env` 加载的,.env 里只要
       存在同名键(哪怕空的)就会盖掉命令行传进来的 =1,而且不报错。所以 .env.example 里
       它只以注释形式出现 —— 一个「示例文件顺手写全」的习惯会直接让开关失效。
    
    2. 开关生效后 `[TaskQueue] 🚀 已启动` 仍会打印,那是另一个模块:services/task-queue.js
       (ArenaSK 时代 /api/claude-chat 的队列,routes/claude-chat.js 模块加载时起),
       和批 3 的 services/task-scheduler.js 同名不同物。它的心跳只扫内存里的 this.tasks,
       不碰 system/agents/,不是干扰源。名字撞车,容易误判成开关没生效。
    
    文档同步:
      - docs/done/claude-cli-session-leak.md §七 重写(原文写的是「得让测试隔离,或跑前停心跳」,
        现在后者已实现,改成开关的用法 + 硬判据 + 上面两个坑);原第 2 条降为 §七之二
      - CLAUDE.md 测试命令块加一行(这是找「怎么跑测试」的人真正会看的地方)
      - docs/README.md 索引行补上开关
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »
  • 泄漏被修过一次(310a2b2 / 3e718aa),修完照样漏。第二次排查发现原因不是修错了,而是:
    
        系统里有两个互相独立的会话池,上一次只修了其中一个;而被修的那个,还漏了一条分支。
    
        池 A  routes/agent-chat.js 的 sessions       ← /api/agent/:id/chat,含两路心跳
        池 B  src/core/session-pool.js 的 SessionPool ← AgentManager.callAgent,图执行 / DevLoop
    
    两者没有任何共享代码,回收逻辑各写各的。这个结构性事实此前没有任何一处记着,
    所以第二个人查到同一个症状时会重走一遍全程 —— 这份文档就是为了让第三个人不必再走。
    
    正文八节,除了两个洞各自的成因与修法(b0b2b62 / 2092a2e),有三处是排查方法而非结论:
    
    §三 按 cwd 第三层判断孤儿归属的对照表。两个池子都把 cwd 下沉到运行态目录,
         `_global` / `_no-task` 是 agent-locator 的保留缺省值、两边都会出现,不能靠它区分。
    
    §四 为什么上一版守卫是瞎的。dropSession 和 closeSession 都会让会话从池子里消失,
         黑盒探针两种情况都返回 false —— 差别只在子进程死没死,而那是探针看不见的维度。
         选探针要问的不是「能不能测出正确行为」,而是「能不能区分正确行为和这个具体的错误行为」。
    
    §八 三步定位脚本,外加一条:先确认跑着的服务器进程是什么时候启动的,再去看代码。
         本次排查中,正在跑的实例比修复 commit 早 18 秒启动,代码里有的修复它并没有。
    
    线上验证(PID 63099,13 分钟窗口两轮心跳):触发 5 / 完成 5 / 回收 5,峰值子进程 3、稳态 0。
    17:13:32 那个 3 正是泄漏时代的签名(cto+coo+qa-judge 同秒触发),清理前那批孤儿一个都不回收,
    现在 30 秒内全部释放。窗口内没有失败心跳,所以 2092a2e 那条 catch 路径是靠单测的变异检验
    保证的、不是靠线上观察 —— 文档 §六 里写明了,没算成已验证。
    
    docs/README.md 同步加索引条目(no-dead-path-references 守卫 4 条全绿)。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse Dir »