• 验证阶段真查出一个 Phase 1/2 都没顾上的真实漏洞:agent-chat.js(/api/agent/*)一直靠
    :agentId 里的 "companyId:role" 命名空间前缀(locator.companyStateDir 解析)区分会话
    属于哪家公司,但这个文件从只挂了 requireAuthOrInternal(登录即可),没有归属校验。
    curl 验证:任意登录用户对 GET /api/agent/{别人的companyId}:{role}/conversations
    依然 200,能跨租户读别家公司的 agent 会话。
    
    修法跟 company.js 同一套思路:router.param('agentId', ...) 解析 : 前的 companyId 段,
    过 canAccessCompany。三个例外:①没有 : 前缀的全局 agent(master/org-innovator 等,
    落 _global)不做归属校验,本来就全系统共享;②内部自环调用(req.user.internal)直接
    放行,招聘/训练自动流水线要能打到任意公司名下;③admin 不受限制。
    
    新增 agent-chat-company-gate.test.js:直接拿 Express 暴露的 router.params.agentId[0]
    单测这个 param handler,覆盖同公司放行/跨公司404/admin不受限/公司不存在404/全局agent
    放行/内部自环放行六种情况。顺带修好一个连带失败的既有测试文件
    (agent-chat-tenant-isolation.test.js,zz-tenant-alpha/beta 同样是从没真正建过的
    虚构公司 id)。
    
    验证:curl 复测跨租户读会话从 200 变 404,owner/admin 依然 200,全局 agent 不受影响;
    真实浏览器用全新账号确认 CompanyDashboard.vue 对"没有可用公司"已有现成空状态,不需要
    新写前端代码。全量 vitest 1433 passed,3 个无关既有失败不受影响。
    
    至此 38 号文档 Phase 0/1/2/3 全部完成。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse File »

  • ## 病症
    
    agent-chat-tenant-isolation.test.js 每跑一次,往共享生产库 data/graph.sqlite
    落 2 条 goal + 2 条 task。实测 29→31。库里 31 条 goal 里 **22 条是它的残留**,
    测试期间一直全绿。
    
    根因是批 5 的存储迁移留下的半截清理:/task/dispatch 的元数据从
    system/tasklog/*.json 换进了 tasks 表,而这个用例的 afterAll 只会清那个目录 ——
    清理代码还在、清的东西已经不在那儿了。
    
    ## 这是第四次,但换了个方向进来
    
    前三次(BENCHMARK_DB_PATH / USERS_DB_PATH / SKILLS_DIR,记在
    test-isolation-env.test.js 文件头)都是「设了 env,生产代码不读」。
    那条守卫查的正是这个形态。
    
    这次是**一个字都没设** —— 没有可查的东西,守卫自然查不出来。
    静态扫源码也判不出「这个测试会不会开库」(要跨 require 链推导)。
    
    ## 修法
    
    1. 用例自己开一次性库(fs.mkdtempSync + GRAPH_DB_PATH),afterAll 连目录删掉。
       赋值必须在 require 路由**之前** —— graph-db.js 的 DB_PATH 是模块级 const。
    2. graph-db.getDb() 加运行期闸门:VITEST 为真且没设 GRAPH_DB_PATH → 抛,
       报错里点名 env、点明「要在 require 之前设」。
       放在 getDb() 不放模块顶层:只为取常量而 require 是合法用法
       (goal-task-model.test.js 就这么用),顶层抛会误伤。真正开库才是越界那一刻。
    3. 守卫 graph-db-prod-guard.test.js,4 例:撞库要抛且报错可照做、设了 env 要能开、
       没有 VITEST 时不生效(防止把生产一起锁死)、样本非空。
       反向验过:注释掉闸门那一行,第 1 例立刻红。
    
    ## 顺带修一条 flaky(我自己上一版留下的)
    
    agent-docs-port.test.js 先 walk 出文件清单再逐个读,中间别的用例把 zz-* 夹具的
    运行态目录清掉 → ENOENT。**报错长得像端口违例,其实跟端口无关**,实测 8 次跑中 2 次红。
    只放过 ENOENT 一种(文件没了),其它读错误照抛 —— 一律 try/catch 吞掉的话,
    权限错、编码错会被当成「无违例」。
    
    ## 存量清理
    
    删掉生产库里 created_by LIKE 'zz-tenant-%' 的 22 goal + 22 task
    (备份 /tmp/graph.sqlite.bak-c3a5d46)。零 run 引用它们。
    其余 9 条 goal 是真实数据,一条没动。
    
    全量:136 文件 / 1276 测试,连跑 8 次全绿(改之前 8 次里红 2 次)。
    跑完后生产库行数零增量。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »

  • 设计见 docs/done/system-design/28-agent-registry-unification.md。
    
    改造前 Agent 本体散在三处(system/agents/ 11 个、system/templates/ 50 个、
    data/companies/{id}/agents/ 17 个),同一个 AgentScaffold 被三个 baseDir 实例化。
    后果是同一角色在 N 家公司下有 N 份互不相干的副本,模板更新不会同步;
    org-coder / org-planner 这类走 hireFromBaseMetaAgent 造出来的本体
    legacy_path 指回自己公司目录,永远无法被第二家公司复用。
    
    本次:
    - G1 单一注册表:system/templates/ 整体并入 system/agents/,base → _base。
      7 个同名 id 逐个裁决,被丢弃的一份归档到 docs/_archive/ 而非删除。
      source_kind(template/global_agent/company_hired) → origin(builtin/created)。
    - G2 运行态下沉:CLI 的 cwd 从本体根改为 system/agents/{aid}/{cid}/{taskId}/。
      memory / conversations 落公司态 {aid}/{cid}/,按公司隔离不串。
      sessionPool 的 key 含 (companyId, taskId),两家公司调同一 agent 不复用会话。
    - G2b 产物不下沉:交付物仍落 data/companies/{cid}/,system/agents/ 只留运行痕迹。
      写入边界按链路分叉——graph 节点走节点私有目录(被 indexNodeOutputs 索引),
      chat 走公司 workspace,同一提示词里不再出现两条互斥指令。
    - G3 公司只存引用:data/companies/{id}/agents/ 删除,新增 company_agents 关联表。
      不复用 org_graph_nodes——后者是执行流图,work 层本体被雇时不写它,天生覆盖不全。
    - G4 缺则创建:本体缺失时从 _base 复制骨架进 system/agents/{id}/,
      agent-creator 填 agent.md/soul.md 后才从 draft 转 active(哨兵判据,
      骨架未填时哨兵仍在,不许被 hire)。产物即刻是全系统可复用的本体。
    
    新增 server/services/agent-locator.js 收编原先散在 6 处的寻址逻辑。
    
    边界守卫(graph-engine)的豁免从「本体根上五个文件名」放宽为整棵 system/agents/:
    新本体的骨架本来就要进 git,gitignore 挡不住 ?? system/agents/{newId}/,
    旧判据会把一个真正成功的招聘节点判成 boundary_escape fail。
    
    存量迁移见 scripts/migrate-agent-registry.js(幂等,备份到 data/_migration-backup-*)。
    
    真 Claude CLI E2E 已验证:新建公司 → orggraph-planning 自动规划 →
    自动招聘 org-planner/org-coder/org-validator 三节点流水线;
    data/companies/{cid}/agents/ 不存在,company_agents 4 行,
    system_agents 56→56(零新建私有本体,纯复用),git status 零增量。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »