• 27-P4 §一.3 的目标逐字写着「解除『一家公司同时只有一个 active
    root run』约束 —— P3 v1 用一个唯一索引强制它,并行能力具备后应
    放开」。本文档的批 4 在做同一件事。
    
    划清边界:放开约束的设计归 27-P4,本文档只负责在它之上定义
    「谁来排队、按什么序出队」。两边各写一版会产生两套并发守卫 ——
    而这次要删的正是最后一道 DB 兜底,守卫分裂的代价特别高。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »
  • 并行的 agent 重构那条线同步来的,已核实三个函数都在:
    - agent-locator.js  missingBodyDefinition()   判什么算没填完
    - graph-service.js  promoteDraftIfComplete()  转正动作
    - graph-service.js  isUngraduatedStatus()     hire() 挡人的判据
    
    关键是最后一个只挡 draft / training 两个状态,不是「≠ active 就挡」。
    库里有 36 个本体的 status 是 enabled/idle/ready/trained,按「不等于
    active」判会被全部误判成没填完 —— 这个坑已经被踩过一次。
    
    取值域的唯一持有者是 graph-service,不要在别处复述 —— 与本文档
    §六.3 记的 canDispatch 教训(前端复述了一份取值域还多写一个
    blocked,导致公司失败一次后再也下不了任务)是同一个病。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »
  • 另一条工作线正在做 agent 目录结构重构(system/templates 并入
    system/agents),约 900 个变更尚未提交。逐条核实交集:
    
    好消息 —— 本文档引用的全部函数/常量(settleRun / markRunReady /
    stopRun / defaultPlanWorkGraph / PLAN_MAX_ROUNDS /
    writeTaskGoalArtifact / reportRunOutcome / ACTIVE_ROOT_RUN_STATUS /
    saveTaskMeta / getAggregatedTasks)在 650 行改动后全部存活,五条
    行为性结论逐条复验仍成立,work-graph-db.js 完全没被碰(第二轮
    复核最关键的那批发现不受影响)。27-P3/P4 那条「只写函数名不写
    行号」的体例在这里直接兑现了价值。
    
    坏消息 —— §四.9 有一条写反了,已纠正并留档:
    - system/templates/ 彻底取消,本体落 system/agents/task-planning/
    - _registry.json 不再是数据源头(seedAgents 直接 readdirSync 扫
      目录当真相,registry 只按 id 补 benchmark_score),所以「不登记
      会把 CI 跑红」不成立 —— 建目录才是关键动作,登记是可选的
    - 真正的闸门是新增的「毕业」判据:agent.md + soul.md 非空且不带
      _base 骨架哨兵,否则 status 停在 draft、hire() 返回
      body_not_ready。「先建骨架后填」的中间态雇不进公司
    - 本体正文路径三条硬规矩(cwd 深度 3):自身文件 ../../、仓库根
      ../../../../../、交付物必须用 $W 绝对路径。写错全都不报错、
      只静默降级 —— 静默故障家族的最新成员
    
    排期影响:批 1 照常(work-graph-db.js 无人触碰);批 2 的
    task-planning 本体等重构落地后再建,否则要按旧形态做一遍再改;
    批 5 开工前重新核 agent-chat.js(+455 行)。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »
  • companyService.get 已经在读这个文件,零新增读路径;建表要多一张表、
    一套读写、一次迁移,而目前公司级配置项只有这一个。涨到 3 个以上时
    再考虑建表。
    
    这是 P3C 最后一个开放问题,§十一 至此全部关闭。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »
  • R-20.6:
    1. 退役 /api/goals 与 /api/company/:cid/goals 两个 OKR 别名,确认执行
    2. goal 级验收仍用 org-validator,在 goal 层再调一次同一个本体。
       不复用 task 级结论 —— 两次验的是基数不同的东西:task 级问
       「这一个 task 的 task-goal 达成没有」,goal 级问「N 个 task
       合起来人要的东西做出来没有」。单 task 的 goal 跳过这次调用。
       goal 状态机加 failed,判词落 goals.verdict
    3. 预算先不考虑,不做 goal 级闸门;但 planning_tokens /
       validation_tokens 两个记账字段保留 —— 它们不是闸门,是让
       goal 层那两次 agent 调用的花费可见
    4. queued 开放改 depends_on。当初担心的「改完位次怎么算」不成立:
       queuePosition 只按 priority→seq→created_at 排,depends_on 决定
       的是够不够格出队,两者正交
    5. 两套任务体系统一到 tasks 表,新增 §十二(批 5)
    
    定案 5 核实出一个反直觉的前提:两套不是并列的,新体系的回调链路
    长在旧体系身上 —— reportRunOutcome 收敛后调的正是
    /api/agent/task/report。所以「删掉另一套」= 删存储与会话反推
    (system/tasklog + TaskService.getAggregatedTasks),不能删入口
    与回调:/task/dispatch 的 URL 与请求体写在 tools-base.md 里,
    改它等于同时改所有 agent 的提示词。
    
    tasks 表为此吸收三个字段(executor / assignee_agent_id /
    parent_task_id):agent 派单与 graph 执行的载体确实不同,
    硬说成一回事是骗自己;调度器只管 executor='graph'。
    顺带修好:派单去重从扫目录变一条 SQL,两套 T- id 合一。
    
    开放问题 2/4/6/7 全部关闭,只剩 5(max_parallel 放哪)。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »
  • 上游失败时下游自动转 blocked 已定案,开放问题里还留着同一个问题
    的疑问句 —— 这正是「代码改了、文档停在上一轮」那类漂移。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »
  • R-20.5 四条:
    1. task-planning agent 提进 v1(原计划 v2 人手拆)。产出一律 draft
       清单,人确认编辑后才下达 —— 那一步是唯一一道成本闸门,
       拆出 5 条 task 就是 5 份 DEFAULT_TASK_BUDGET
    2. 并行仍留批 4,v1 只排队(max_parallel_tasks=1,唯一索引不动)
    3. manual 任务不参与自动出队:startRun(manual) 只点亮入口就停下等
       /next,而 run 已经是 running 占着坑,自动拉起会堵死队头
    4. 上游失败 → 下游自动推导为 blocked 并标红,给「重跑上游」和
       「强制放行」两个出路。blocked 每次 tick 重算而不落死,
       上游重跑成功后下游自己回 queued
    
    定案 1 牵出一处新缺陷:task-planning 跑在 goal 层、任何 run 存在
    之前,它烧的 token 没有预算池可扣 —— 正是 defaultPlanWorkGraph
    注释里点名的「隐形的一半花费」在 goal 层的新实例。上一轮刚以
    「零消费方」为由砍掉的 goal 级预算字段,以记账字段 planning_tokens
    的形式回来(闸门仍不做)。
    
    链路照抄 defaultPlanWorkGraph 不另造:调 agent → 校验 → errors
    原样回喂,最多 3 轮;3 轮不过降级成 1 条同描述的 task,绝不能把
    goal 卡在 planning。新本体必须与 _registry.json 登记同 commit,
    否则 template-refs.test.js 当场把 CI 跑红(§八.21 有前科)。
    
    验收 19-24 新增:拆分正常 / 失败降级 / 记账 / 不该花钱的路径不花钱
    / 上游失败下游标红且可恢复。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »
  • 逐条对着代码核初稿,最要命的一条是基础事实搞错了:
    
    - createRun 在建行的事务里就按 readDefGraph 把 graph_run_nodes 全插好了。
      初稿三处基于「queued run 没有节点行、进去就是空指针」的论证全部作废。
      真实情况是 queued run 与 ready run 在数据上只差 run_status 一个字段,
      所以「靠没有节点行自然报错」那道想象中的防线根本不存在,
      唯一的闸门是 advanceOne 里 run_status !== 'running' 那一句,必须加断言钉死。
    
    由此派生出一个既存、但被排队从毫秒窗口放大成必然事件的缺陷:
    节点行在 createRun 时快照,而 getRunState 每次读都取当前定义。
    排队期间点「重新规划组织」→ 新节点没有 run 行 → 出队即卡死。
    补 syncRunNodesToDef,出队前对齐。
    
    其余六处:
    - 出队原语写错:markRunReady 把 from 写死成 planning,复用不了;
      正解是 updateRunStatus(runId,'queued','ready') 这一条条件更新
    - 唯一索引冲突是 throw 不是 changes=0,初稿的错误处理只覆盖一半
    - 触发点枚举本身是漏的:stopRun 与预算耗尽→blocked 两条最常见的
      释放路径都不走 settleRun。改为挂在唯一漏斗 transitionRun 上,
      一个钩子覆盖全部路径(枚举法在这里靠不住,而漏的症状是静默的)
    - report_to 只活在请求闭包里,排队后回调链路静默断掉 → 必须落库
    - okr_node_id 逐 task 下发会反复覆写同一个 OKR 节点,
      done 会被后来的 failed 翻掉 → task 的 run 一律不带 okr_node_id
    - manual 任务占着 running 等人点「下一步」,会永久堵住队头
      → 不参与自动出队
    
    补漏:存量回填脚本(不做的话批 1 反而让历史任务更看不见)、
    任务级 rerun 与节点级 retry 的命名撞车、queuePosition 排序口径
    必须与调度器同源、砍掉没有消费方的 goals.budget_json。
    
    错误结论留档不删(§三 ⚠️ 块 / §五.1 / §九.1 开头)——
    它们是最容易再犯一次的那类。验收从 12 条涨到 19 条。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »
  • 控制台走查暴露的「一个 company 只能有一个任务」,根因不是并发约束,
    是「人类提的需求」和「机器执行的单元」被压在同一条 root graph_run 上。
    
    三个实地核实的前提,让这次不是发明新概念:
    - 27-NAMING §四 早就定义了 goal 1 : task N 的基数
    - graph_runs.goal_id / task_id 两列早就在,company.js 注释也写着
      「三者基数不同不可混用」—— 但全仓库没有任何写入方,goal_id 是悬空外键
    - G- 前缀已被 OKR 正名释放;/api/goals 与 /api/company/:cid/goals 这两个
      OKR 向后兼容别名全仓库零调用方,可以退役后把路径要回来
    
    设计要点:
    - goals / tasks 两张新表 + graph_runs 新增 run_status='queued'
    - queued 的唯一理由是把出队的并发临界区交给既有唯一索引兜底:
      idx_graph_runs_one_active_root 覆盖 ready/running/paused 而不覆盖 queued,
      超发会被索引直接拒绝,不需要应用层的「先查后插」
    - 排队推翻了 P3「拒绝而不排队」的定案,但那条定案的理由(没有出队 worker =
      静默丢任务)今天仍成立,所以调度器的四个触发点是功能主体而非收尾
    - 已下达的描述冻结:入队即写 task-goal.json 并被 describeTask 消费,
      改库不改 artifact 会让两份对不上,两份都改等于篡改审计输入
    - 现有 T-${Date.now().toString(36)} 在「一个 goal 批量建 N 个 task」下
      同毫秒必撞,且 tasks.id 是主键 —— 改用仓库既有约定的 4hex 后缀
    
    R-20 四条定案回记至 27-requirement.md。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »