• company-service.js:company.json 加 ownerId(无 SQL 表,纯 JSON 字段);create() 接收
    ownerId;list({ user }) 按传入用户过滤,不传就不过滤(company-heartbeat-service.js 等
    系统内部巡检要看全部公司);新增 canAccessCompany(company, user) 作为全仓库唯一一份
    归属判据(admin 不过滤,判负一律 404 不是 403,不暴露"这个 id 存在只是不是你的")。
    
    company.js 用 router.param('companyId', ...) 统一收口(约 50 条路由,含 okrPath() 系列
    动态路由)。graph-run.js 的两个挂载点参数形状不一样,设计阶段的描述不准确,实现时才
    发现:companyRouter 唯一路由是 /:companyId/graph-runs 直接查;主 router 全部路由是
    /:id/...,:id 指的是 run 不是公司,改成先查 run 的 company_id 再判断,run 不存在或
    公司不是你的统一回"run 不存在"。devloop.js 用 :pid 反查 company_id;POST /projects
    单独校验 body 里的 company_id(放在基本字段校验之后,避免归属检查打乱输入校验的错误
    优先级);GET /projects 按归属过滤列表。
    
    okr.js 最终没有按原计划接入 companyId 归属校验——实现前查证发现 OkrDashboard.vue
    挂载的 /okr 页面全站没有任何导航入口指向它,是个孤儿页面,给访问不到的页面建"选公司"
    前端交互不划算,改成 requireAdmin(跟 dream.js 同款),先堵住直接拼 URL 看到跨公司
    聚合数据的口子。真正在用的公司级 OKR(company.js 的 /:id/okr)已随 company.js 一起隔离。
    
    存量数据迁移:scripts/backfill-company-owner.js(npm run backfill:company-owner),
    两家存量公司已划给种子账号,幂等验证过。
    
    8 个既有测试文件用的公司 id 都是从没真正建过的字符串标签,挂锁后集体 404——新增共享
    helper server/tests/helpers/ensure-test-company.js 修复;两处原有的"跳过已有
    company.json 的目录,那是真公司"防御逻辑,判据从"有没有 company.json"改成"ownerId
    是不是 -1 这个测试专用标记",否则新出现的测试夹具会被误判成真公司永远不清理。
    
    验证:真实 curl 走过(admin 看到全部存量公司、新用户看到空列表、新用户拼 URL 访问
    别人的公司 404、新建公司 ownerId 精确落在创建者、admin 和创建者都看得到其他人看不到);
    全量 vitest 1427 passed,3 个无关既有失败不受影响。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse File »

  • 35 号文档剩下的三个提案,彼此直接相关(C 产出 D 消费的证据,B 展示 D 算出的结果),
    一次做完。
    
    提案 D(goal-contract.js 引擎级证据闸门):
      `runBenchmark` 新增 evidence 检测——`evidence_hint` 命中"浏览器/视口/开发者工具/
      console/network/截图"类关键词的维度,必须在 evidence.<dim> 有真实字符串支撑,
      否则该维度判不过(哪怕分数达标)。证据来源两处都认:`--target` 文件自带的
      `evidence.<dim>`,或同目录姊妹判词文件 `attempt-<n>.json` 的 `dimensions[].evidence`
      ——后者是 benchmark-validator/agent.md 早就在教的既有写法,不用 agent 多写一份。
      新增 `dimensions[].evidence_required` 字段随判决落盘。6 条新单测。
    
    提案 C(可复用视觉验收工具):
      新增 scripts/visual-acceptance-check.mjs,四个子命令(overflow/style/console/
      contrast),封装最常见的几类真实浏览器检查(Playwright),agent 通过 bash 直接
      调用,不用每次自己临时想办法(真实撞见过两个极端:一次真写了 Playwright 认真测,
      一次只写了正则解析文本)。配一份不进 vitest 快速循环的独立冒烟脚本(起真
      Chromium,几秒量级)。benchmark-validator/agent.md Step 2 加了引用说明。
    
    提案 B(控制台证据可见性):
      GET /api/graph-runs/:id 新增 benchmarkVerdicts 字段(只读 goal-contract.js 已落盘
      的判决,不重新计算)。NodeDetailPanel 概览 tab 新增"验收证据"小节:逐维度显示
      分数 + 是否有证据支撑,evidence_required 且缺证据的标 ⚠️。纯展示,不改判定逻辑。
      2 条新单测。
    
    全量单测 1012/1012 通过;控制台功能用 Chrome 实测过(截图确认"验收证据"小节正确
    渲染)。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse File »
  • 用户反馈:控制台原来只能逐个节点点「输入输出」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 File »

  • 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 File »

  • R-19.A 把 declareEdgeContract 的调用方补上之后,inboundContracts 终于非空,
    「沿边传递」这类数据流在真跑里生效了(真实规划 agent 自己在边上写出了
    produces/needs 声明)。本次收掉它留下的三个缺口。
    
    1) role 落库(第 14 次「四环漏一环」)
       normalizeContracts 产出 role,declareEdgeContract 入参没有它、表也没这列 ——
       产生 → 传递(丢) → 落库 → 读回。后果不止是控制台不精确:规则 6(data-contract)
       靠「有人 needs 但没人 produces」判错,只存 kind 就没法从库里重算,而
       patchGraph 第 5 步的重新校验读的正是库 —— 增量 PATCH 又恰恰是
       「此前满足的 needs 失去产出方」的唯一发生地,校验偏偏在最该生效的通道上失效。
       - graph_edge_contracts 加 role 列(CHECK + 老库 ALTER 后回填 produces:
         NULL 在规则 6 里既不算产出也不算需求,会误拒一张合法的图;闸门宁可漏判不可错拦)
       - 两层调用点透传 role;readGraph 把 contracts 读回来并递进 validateGraph
    
    2) 控制台三字段(前端在、后端没喂)
       GET /api/graph-runs/:id 补 edges[].contracts / companyRoot / taskFiles,
       否则 R19-C 那三块界面整块降级:声明和索引都在库里,界面上看不见。
       contracts 只在非空时出现,与 failReason 同一个约定。
    
    3) 收拢 companyRootDir/taskDirRel 镜像
       goal-contract.js 里那份镜像靠注释约定「与 graph-engine 逐字同构」维持,
       控制台路由成为第三个调用方时这个约定就不成立了。抽到 company-paths.js,
       GRAPH_RUNS_DIR 改为调用时读(原先两个模块各自在加载时快照,
       加载顺序不同会算出不同的根)。goal-contract 那条「镜像漂了就报警」的用例
       按其自身预告改成比函数返回值。
    
    测试 826 全绿(+11:role 8 / 路由 3),既有断言未改。
    11 处变异逐一验证精确变红后逐字还原;其中一条断言初版在 fixture 上永远自洽
    (图里没有无声明的边),补了一条无声明的边才真正有判别力。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »