Compare commits
8 Commits
cb0257055e
...
4c7580ccda
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c7580ccda | ||
|
|
2a6d902e5d | ||
|
|
0d4c2adc54 | ||
|
|
08db3c2323 | ||
|
|
9f468a13a1 | ||
|
|
1bb4ce978e | ||
|
|
0a8a9e60bc | ||
|
|
16473e7260 |
@ -6,7 +6,7 @@ description: >
|
||||
成为每个项目的贴身导师。炼境本身亦被纳入其中,
|
||||
形成可自我进化的开发智能闭环。
|
||||
iteration: 1
|
||||
updated: 2026-07-04
|
||||
updated: 2026-08-23
|
||||
agent_button_carrier: tauri
|
||||
|
||||
|
||||
@ -422,7 +422,8 @@ modules:
|
||||
area: backend
|
||||
status: concept
|
||||
progress: 0
|
||||
note: "老板-员工手册隐喻:用户反馈子项目问题 → 结构化落账 → 梦核蒸馏进规则/模板 → 批量分发 → 飞轮观测生效。三缺口:反馈入口、反馈进梦核高权重输入、接入包批量重分发"
|
||||
note: "老板-员工手册隐喻:反馈→落账→梦核蒸馏→批量分发→飞轮观测。2026-08-23 沉淀「开发侧世界模型透镜」:三闸门(跨项目edges/全局地图/模式库)+ 三投影准入律;📋 notes 档案落地卡就绪(可拆除性唯一硬违规修复)"
|
||||
updated: 2026-08-23
|
||||
position: [1250, 650]
|
||||
|
||||
- id: mcp-single-server
|
||||
|
||||
@ -69,6 +69,60 @@ MANAGED 块警示(5b0b068)、Bug Fix/Feature 分类 + S 级轻量卡 + 汇
|
||||
- ~~src-tauri/ 下空路径污染残留~~ → 2026-07-18 辩证收缩后三步收官:①9 个污染文件已移出(暂存 `%TEMP%\liangjing-pollution-20260718`);②两条空路径僵尸登记(agent编排界面(opencode)/银龙集团应用)已 unregister(磁盘无对应目录,实为死登记);③辩证挖出 **inject 链路漏拦同一空路径洞**(`project_root()` 对空串 win_path 穿透写 cwd,正是 settings.json/liangjing.json 污染的来源)——已单点补 `validate_registered_path`(拒空+拒相对路径)+ 2 条回归测试。空路径事故至此两链路(apply/inject)全堵
|
||||
- envoy.md 硬门槛已进模板,**需重建安装炼境后 apply 才会分发到子项目**(模板打包在二进制资源)
|
||||
|
||||
## 开发侧世界模型透镜(2026-08-23 辩证收敛)
|
||||
|
||||
> 源头:enterprise-system 使者回传「炼境=开发侧世界模型容器」(2026-08-23)+ 业务侧四载体
|
||||
> (vision-world-model.md / estate1-world-model.md / hub-relation-catalog.md / hub-matrix-biz-ecology.md)回顾。
|
||||
> **合题:世界模型是透镜,不是工程**——用透镜照出真实病灶就修,其余全部挂闸门。
|
||||
|
||||
### 同构映射(业务侧 ↔ 开发侧)
|
||||
|
||||
R 规则层=CONVENTIONS 规则库(炼境强项,业务侧反而隐式)|E 实体层=项目/模块/任务卡/服务器(实体丰富、跨项目关系贫乏)|A 资产层=接入包(唯一模式雏形)|地图=单项目蓝图画布(无全局)|可拆除性=资产纯文件 git(notes 是唯一违规点)。
|
||||
|
||||
### 两处判断修正(辩证结论,防后续会话重新推演)
|
||||
|
||||
1. **「独立世界仓库」被否**:现在只有一个住户(notes 档案),为一个住户建仓库违反晋升阶梯(第二个场景才晋升)。炼境自身仓库本来就是事实上的元仓库,跨项目资产先住这里。
|
||||
2. **可拆除性缺口比直觉窄**:飞轮数据可从 git 历史重生(ingest_git_history=重生配方),不违规;**唯一硬违规是 project_notes**(复盘笔记+使者回传,原创不可再生,只活在 SQLite)——即下方 A 卡。
|
||||
|
||||
### 三个闸门(等真实场景敲门,禁止提前建设)
|
||||
|
||||
| 候选 | 闸门条件 | 备注 |
|
||||
|------|---------|------|
|
||||
| 跨项目 edges | 第一个真实跨项目查询需求(最可能从梦核来) | 方案已定:自省派生 ∪ 显式声明(继承 hub-relation-catalog) |
|
||||
| 全局地图视图 | edges 落地之后 | 开闸时先辩证「矩阵 vs 画布」——manage-multi-view 已承载一半需求,勿撞车;节点须双承载(入口+健康度) |
|
||||
| 模式库 | ⚡ 闸门已敲响(2026-08-23 第三候选到位,待用户决定开建) | 接入包=第一个模式,库=接入包机制泛化;三候选:DSH 接入模板、子主题规范、**dev path 定位投影** |
|
||||
|
||||
### 三投影准入律(新资产类型的验收清单)
|
||||
|
||||
任何新世界模型资产类型,三投影不齐不算入模:**文件形态**(git 可拆除)+ **MCP 工具**(agent 可消费)+ **UI 投影**(人可终验)。
|
||||
|
||||
### 已否决方案存档:用 enterprise-system 框架整体重构炼境(2026-08-23 辩证,用户暂存待续)
|
||||
|
||||
**结论:整体重构否决,机制移植推荐(种子拿来,土壤留下)。**
|
||||
|
||||
三个硬阻断:① 炼境命根子是"本地之手"(启动编辑器/写本地文件/git/托盘),web 栈给不了,重构完仍需本地 daemon,架构更重;② 数据哲学正面冲突——enterprise「页面身份在数据库」vs 炼境「可拆除性:资产=文件在 git」,搬进配置引擎 DB 是哲学掉头;③ 单用户桌面背不动多用户 web 引擎的权限/隔离死重。收益错位:世界模型瓶颈(edges 无数据/无消费场景)没有一个是 UI 框架造成的。
|
||||
|
||||
**种子清单**(可移植机制,经模式库通道逐颗引入):dev path 定位投影(下方 💭 卡)、view-lab 多维视图交互(做 manage-multi-view 时借)、关系目录方法论(已继承为 edges 方案)、Hub 矩阵交叉点双承载(地图开闸时用)、注册表反转三件套(设计纪律)。
|
||||
|
||||
**反转条件**(出现再重估引擎化):① 需要多端/远程访问 → 届时是"炼境长出 web 投影"非重构本体;② 实体清单页持续增殖(现 15+ 张)→ 届时炼境内部长轻量配置化表格引擎,只管新页不回迁旧页。
|
||||
|
||||
### 💭 DevPath 卡 1:模板契约层「定位投影」
|
||||
- status: concept
|
||||
- 内容:AGENTS.md.tmpl agent 按钮节新增「定位投影(dev path)」条——UI 项目应提供 DEV 浮层,一键复制"当前页面 → 代码/配置锚点"(ROUTE/CODE/DATA/STATE 四段契约),参考实现 enterprise-system `components/DevPathHint.tsx`;自身 AGENTS.md + meta-rules 同步。S 级,1.7.0 若仍未分发可补遗不升号
|
||||
- 概念定位:dev path = 人这边的发话按钮——agent 按钮让 agent 能做,dev path 让人能说(把"我在这里"的手势转成 agent 可解析地址);搭配截图 = 人语视觉参照 + agent 语机器锚点双通道
|
||||
|
||||
### 💭 DevPath 卡 2:炼境自建 DevPathHint(吃自己狗粮)
|
||||
- status: concept
|
||||
- 内容:新增 `src/components/DevPathHint.tsx` + App 挂载,DEV 环境左下浮层:当前路由 → 页面组件文件路径 → 选中项目/模块 ID,一键复制。M 级
|
||||
- 注意:炼境页面是代码路由非配置驱动,价值低于 enterprise 版(那边 grep 会扑空,这边 grep 通常能中)——实现时保持轻量,勿照抄其配置推导层
|
||||
|
||||
## 任务卡
|
||||
|
||||
(concept 阶段,L 级——待 /architect 设计确认后由 /splitter 拆卡)
|
||||
### 📋 notes 档案落地(可拆除性修复:双写 + 存量回填)
|
||||
- status: todo
|
||||
- complexity: M
|
||||
- files: src-tauri/src/mcp_tools.rs, src-tauri/src/db.rs
|
||||
- acceptance: agent_verify: [Tauri command] append_project_note(pid, content) → DB 有记录**且** `.blueprint/notes-archive.jsonl` 尾行 JSON 可解析出同一 content;存量回填命令执行后 JSONL 行数 = project_notes 表行数;cargo test 覆盖双写 + 并发追加不交错
|
||||
- 备注:project_notes 是全系统唯一不在 git 的原创资产(飞轮全部原料)。格式选 JSONL 而非 md——机器可重放重建 DB,才是真「重生配方」。归宿:炼境仓库 `.blueprint/notes-archive.jsonl`,沿 usage.json「炼境自动写文件 + chore commit」先例。这即本模块缺口①「结构化落账」的地基
|
||||
|
||||
(其余 concept 阶段,L 级——待 /architect 设计确认后由 /splitter 拆卡)
|
||||
|
||||
@ -55,6 +55,13 @@
|
||||
|
||||
> 完成记录(2026-07-03):能力双投影概念的首次实践。cargo test 全绿;实测验证由 agent 通过 MCP 端点亲自按下这三颗按钮完成。
|
||||
|
||||
### ✅ 飞轮派生数据工具输出 staleness 标注
|
||||
- status: done
|
||||
- complexity: S
|
||||
- files: src-tauri/src/db.rs, src-tauri/src/commands/gitea.rs, src-tauri/src/mcp_webhook.rs, src-tauri/src/mcp_tools.rs
|
||||
- acceptance: agent_verify: [cargo test] touch_sync_state 后 read_sync_state 返回时间与分钟数、未知 domain 返回 None;get_pr_events / get_commit_metrics 输出首行含「⏱ 飞轮数据最近同步」;cargo test 通过
|
||||
- 备注:世界模型自洽——模型可以过期,不能不知道自己过期。实锤:get_pr_events 延迟致 /ship 误判无 open PR(enterprise-system 2026-07-28 回传)。get_ci_status 是实时 Gitea API 调用,不在范围内。sync_state 单行 domain='flywheel',轮询成功与 webhook 落库两处 touch
|
||||
|
||||
### 💭 能力双投影:后续扩展(R12 规则化 + 更多按钮)
|
||||
- status: concept
|
||||
- 侦察→驻军(2026-07-03): agent 走流程验证=侦察(智能、贵、一次性验收),vitest/cargo test=驻军(固化、免费、高频回归);agent 验证通过的关键路径顺手固化为测试(接宪章"坑驱动增量"),一次性验收不固化(少而稳>多而脆)。不引入 BDD/spec 框架——acceptance 字段已是人机共读的 spec
|
||||
|
||||
@ -160,6 +160,14 @@
|
||||
- acceptance: [MCP tool] get_diagnostics(或 verify_onboarding 检查链)新增「沉默项目」信号:项目近 30 天 commit_metrics 有数据但使者回传(list_envoy_returns 同源数据)为 0 → 列出项目名 + commit 数,提示去该项目跑 /envoy;近 30 天有回传或无 commit 活动 → 不报
|
||||
- notes: U2(子项目侧 Stop hook 自动触发 /envoy)经多角度辩证否决(2026-07-15):自动化触发会拆掉人肉过滤层,诱导 agent 用 under_validation 噪声交差灌满回传通道——伤「择」换「环」转速,本末倒置。正解是炼境侧可观测性:让遗忘可被看见(信号驱动),人留在过滤环里决定是否回传。同时销掉原 B4 后置欠账(体系遵守度检查)
|
||||
|
||||
### ✅ V2. AGENTS 模板注入「同源同边界 + 操作复刻」设计原则(v3.1)
|
||||
- status: done
|
||||
- done_note: 2026-08-23 完成。四刀外科手术:节首总纲(本体+双投影/先本体后投影+原型豁免)、第1条追加复刻推论+三分定位启发式、human_verify 补否决理由记录一句、版本 1.6.1→1.7.0;炼境自身 AGENTS.md 块内同步、agents-meta-rules.md 新增同源同边界节;cargo test onboarding 13 全过。补遗(同日):节尾收束语「本体先行,边界一次,操作同语——人指的问题 agent 走得到,人在意的点 agent 读得懂」+ 需求对称两时间尺度脚注(当下=同源结构直接保证;跨会话=否决理由落账→复盘笔记→梦核,机制通道挂 governance-feedback-loop 缺口①)。1.7.0 未曾分发故不再升号。分发待重建安装后批量 re-apply
|
||||
- complexity: S
|
||||
- files: src-tauri/resources/onboarding/AGENTS.md.tmpl, AGENTS.md, docs/templates/agents-meta-rules.md
|
||||
- acceptance: agent_verify: [文件] AGENTS.md.tmpl「agent 按钮与验证路径」节含「同源同边界」「操作序列 agent 皆可复刻」「三分定位」表述,MANAGED 版本 1.6.1→1.7.0;炼境自身 AGENTS.md 块内同步;cargo test onboarding 通过
|
||||
- notes: 2026-08-23 多角度辩证收敛(v3→v3.1 外科手术版):真实增量仅三个半(先本体后投影时序/复刻+复现路径/三分定位启发式/飞轮转译轻写一句),其余为已有六条重述不重复注入;三分定位从"定律"降级"启发式"(crypto.randomUUID 环境层实锤:本体投影都没病,病在环境);原型探索豁免时序约束;飞轮转译不承诺机制(采集通道挂 governance-feedback-loop 缺口①)
|
||||
|
||||
## 复盘笔记
|
||||
|
||||
【复盘】U1 全托管文件升级通道 + 批量重分发(2026-07-15)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,8 @@
|
||||
回顾本次会话的完整对话,识别有价值的洞察。
|
||||
跳过:纯代码实现细节、具体 bug 修复、一次性操作记录。
|
||||
|
||||
> ⚠️ **炼境定位讨论不得漏判**:凡涉及「炼境自身定位 / 缺口 / 演进方向 / 与其他工具的对比」的讨论,即便看起来像聊天而非技术实现,**默认视为体系级洞察,列入带回候选清单**。此类内容在历史会话中曾被漏传(判定为聊天),经用户追问才补发。
|
||||
|
||||
## Step 3:分类每条洞察
|
||||
|
||||
**前置硬门槛(先于一切分类判断)**:问自己——**任何有经验的工程师是否会提前想到这一点?**
|
||||
@ -34,6 +36,8 @@
|
||||
## Step 4:发回炼境
|
||||
|
||||
对每条「带回」洞察,单独调用一次 `mcp__lian-jing__append_project_note`。
|
||||
|
||||
> **MCP 不可用时的降级**:若 `mcp__lian-jing__append_project_note` 报连接错误,重试 1~2 次仍失败,则将所有待回传内容按 Step 4 格式整理成一段文本,输出到对话让用户看到,并提示:「MCP 断连,请复制以上内容到炼境会话手动执行 `/envoy` 回传,或重连后重跑本命令」。
|
||||
- `project_id`:来自 Step 1
|
||||
- `content` 格式(严格遵守):
|
||||
|
||||
|
||||
16
AGENTS.md
16
AGENTS.md
@ -138,7 +138,7 @@ docs/templates/ 炼境接入包模板草案(设计层)
|
||||
完整规则(迭代管理、阻塞处理、复盘笔记等)详见 `.blueprint/CONVENTIONS.md`。
|
||||
<!-- BLUEPRINT_MANAGED_END -->
|
||||
|
||||
<!-- ONBOARDING_MANAGED_START version="1.6.1" -->
|
||||
<!-- ONBOARDING_MANAGED_START version="1.7.0" -->
|
||||
> ⚠️ 本块由炼境版本化托管,升级时**整块原位覆盖**——项目定制请写到块外,块内手改必丢(2026-07-15 炼境自身实锤丢失 5 段定制后新增本警示)。
|
||||
|
||||
## 核心开发约束
|
||||
@ -189,10 +189,14 @@ docs/templates/ 炼境接入包模板草案(设计层)
|
||||
## agent 按钮与验证路径
|
||||
|
||||
功能的本体是代码层的能力;UI 按钮是它给人的投影,**agent 按钮**是给 agent 的投影
|
||||
(可发现 + 可调用 + 有边界的能力声明)。开发任何功能时遵守:
|
||||
(可发现 + 可调用 + 有边界的能力声明)。**任何功能 = 一个本体 + 两个投影,同源同边界**;
|
||||
设计交付时先定本体后盖投影(原型探索不受此序约束,交付前本体归位)。开发任何功能时遵守:
|
||||
|
||||
1. **边界单点实现**:业务校验只写在能力本体层(API/command),UI 只呈现不复制逻辑——
|
||||
否则人与 agent 的验证路径会分裂
|
||||
否则人与 agent 的验证路径会分裂。同源的直接推论:**人的操作序列 agent 皆可复刻**——
|
||||
人报障即复现路径(操作 + 状态),agent 重放至同一状态定位病灶。
|
||||
三分定位启发式:本体重放正常 → 优先怀疑投影层(接线/渲染/状态同步)→ 再查环境差异
|
||||
(安全上下文/网络/OS);重放失败先怀疑初始状态差异,而非否定问题存在
|
||||
2. **载体就近选择**(本项目的 agent 按钮是什么,按项目类型对号入座):
|
||||
| 项目类型 | agent 按钮载体 |
|
||||
|---------|---------------|
|
||||
@ -214,11 +218,17 @@ docs/templates/ 炼境接入包模板草案(设计层)
|
||||
- `agent_verify:` — 机器可断言(HTTP 状态码、数据库记录、函数返回值);stop hook / CI 只验此段
|
||||
- `human_verify:` — 需人眼判断(视觉效果、拖拽手势、30 秒浏览器终验)
|
||||
纯 API / 命令行任务可省略 `human_verify:`;UI 拖拽 / 动画 / 视觉类必须拆,否则 stop hook 无法收敛。
|
||||
human_verify 的否决理由值得记录——它是把体感转译成可断言规则的原料。
|
||||
6. **自验报告纪律**:交人终验前的反馈必须含「**没验什么**」一节(未覆盖的路径、依赖的
|
||||
假设、不确定的地方);自修过程中改了断言/验收标准必须显式声明理由(改功能让测试过是
|
||||
常规,改测试让功能过需报备);agent 自验对 acceptance,人终验对意图——acceptance
|
||||
可能继承需求理解偏差,两把尺子不可合一
|
||||
|
||||
> 收束:**本体先行,边界一次,操作同语——人指的问题 agent 走得到,人在意的点 agent 读得懂。**
|
||||
> 后半句分两个时间尺度:当下会话由同源路径即时对称(反馈天然绑定双方走过的路径);
|
||||
> 跨会话靠否决理由落账(→ 复盘笔记)积累,人反复在意的维度逐步迁移进可断言规则——
|
||||
> 人裁决区是飞轮推进的前线,不是墙上的洞。
|
||||
|
||||
## 多 AI CLI 协作
|
||||
|
||||
本项目可由多个 AI CLI 协同。交接时把结果总结成 3 条传给下一个:
|
||||
|
||||
10
docs/templates/agents-meta-rules.md
vendored
10
docs/templates/agents-meta-rules.md
vendored
@ -109,6 +109,16 @@ AGENTS.md 或 `docs/ai-context/project-brief.md` 描述的现实已经改变。
|
||||
|
||||
三要素缺一不可:**可发现**(清单里有)、**可调用**(结构化命令)、**边界清晰**(通过标准明确)。
|
||||
|
||||
### 同源同边界(设计原则,v1.7.0 起)
|
||||
|
||||
**任何功能 = 一个本体 + 两个投影**:本体是能力层实现(API/command/服务函数),人按钮(UI)与 agent 按钮都是它的投影。同源 = 两投影走同一代码路径;同边界 = 业务校验只在本体层砌一次墙。设计交付时先定本体后盖投影(原型探索豁免此序,交付前本体归位)。
|
||||
|
||||
同源的直接推论:**人的操作序列 agent 皆可复刻**——人报障即复现路径(操作 + 状态),agent 重放至同一状态定位病灶。三分定位启发式:本体重放正常 → 优先怀疑投影层 → 再查环境差异;重放失败先怀疑初始状态差异,而非否定问题存在。
|
||||
|
||||
效果分两层:**防御**——人指的问题即复现路径,agent 走得到;**进攻**——操作成为人机共同语言,人的验收反馈天然绑定双方走过的路径,需求信息对称。对称有两个时间尺度:当下会话由同源结构直接保证(无需额外机制);跨会话需反馈落账(human_verify 否决理由 → 复盘笔记 → 梦核蒸馏),人反复在意的维度逐步迁移为可断言规则——人裁决区是飞轮推进的前线,不是墙上的洞。
|
||||
|
||||
> 收束:**本体先行,边界一次,操作同语——人指的问题 agent 走得到,人在意的点 agent 读得懂。**
|
||||
|
||||
### Acceptance 写法规范
|
||||
|
||||
acceptance 是 agent 自验的唯一判断依据,必须是**可执行断言**,不能是描述性语句:
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
回顾本次会话的完整对话,识别有价值的洞察。
|
||||
跳过:纯代码实现细节、具体 bug 修复、一次性操作记录。
|
||||
|
||||
> ⚠️ **炼境定位讨论不得漏判**:凡涉及「炼境自身定位 / 缺口 / 演进方向 / 与其他工具的对比」的讨论,即便看起来像聊天而非技术实现,**默认视为体系级洞察,列入带回候选清单**。此类内容在历史会话中曾被漏传(判定为聊天),经用户追问才补发。
|
||||
|
||||
## Step 3:分类每条洞察
|
||||
|
||||
**前置硬门槛(先于一切分类判断)**:问自己——**任何有经验的工程师是否会提前想到这一点?**
|
||||
@ -36,6 +38,8 @@
|
||||
## Step 4:发回炼境
|
||||
|
||||
对每条「带回」洞察,单独调用一次 `mcp__lian-jing__append_project_note`。
|
||||
|
||||
> **MCP 不可用时的降级**:若 `mcp__lian-jing__append_project_note` 报连接错误,重试 1~2 次仍失败,则将所有待回传内容按 Step 4 格式整理成一段文本,输出到对话让用户看到,并提示:「MCP 断连,请复制以上内容到炼境会话手动执行 `/envoy` 回传,或重连后重跑本命令」。
|
||||
- `project_id`:来自 Step 1
|
||||
- `content` 格式(严格遵守):
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
<!-- TODO: 列出 README / ARCHITECTURE.md / 其他关键文档及用途。 -->
|
||||
|
||||
<!-- ONBOARDING_MANAGED_START version="1.6.1" -->
|
||||
<!-- ONBOARDING_MANAGED_START version="1.7.0" -->
|
||||
> ⚠️ 本块由炼境版本化托管,升级时**整块原位覆盖**——项目定制请写到块外,块内手改必丢(2026-07-15 炼境自身实锤丢失 5 段定制后新增本警示)。
|
||||
|
||||
## 核心开发约束
|
||||
@ -69,10 +69,14 @@
|
||||
## agent 按钮与验证路径
|
||||
|
||||
功能的本体是代码层的能力;UI 按钮是它给人的投影,**agent 按钮**是给 agent 的投影
|
||||
(可发现 + 可调用 + 有边界的能力声明)。开发任何功能时遵守:
|
||||
(可发现 + 可调用 + 有边界的能力声明)。**任何功能 = 一个本体 + 两个投影,同源同边界**;
|
||||
设计交付时先定本体后盖投影(原型探索不受此序约束,交付前本体归位)。开发任何功能时遵守:
|
||||
|
||||
1. **边界单点实现**:业务校验只写在能力本体层(API/command),UI 只呈现不复制逻辑——
|
||||
否则人与 agent 的验证路径会分裂
|
||||
否则人与 agent 的验证路径会分裂。同源的直接推论:**人的操作序列 agent 皆可复刻**——
|
||||
人报障即复现路径(操作 + 状态),agent 重放至同一状态定位病灶。
|
||||
三分定位启发式:本体重放正常 → 优先怀疑投影层(接线/渲染/状态同步)→ 再查环境差异
|
||||
(安全上下文/网络/OS);重放失败先怀疑初始状态差异,而非否定问题存在
|
||||
2. **载体就近选择**(本项目的 agent 按钮是什么,按项目类型对号入座):
|
||||
| 项目类型 | agent 按钮载体 |
|
||||
|---------|---------------|
|
||||
@ -94,11 +98,17 @@
|
||||
- `agent_verify:` — 机器可断言(HTTP 状态码、数据库记录、函数返回值);stop hook / CI 只验此段
|
||||
- `human_verify:` — 需人眼判断(视觉效果、拖拽手势、30 秒浏览器终验)
|
||||
纯 API / 命令行任务可省略 `human_verify:`;UI 拖拽 / 动画 / 视觉类必须拆,否则 stop hook 无法收敛。
|
||||
human_verify 的否决理由值得记录——它是把体感转译成可断言规则的原料。
|
||||
6. **自验报告纪律**:交人终验前的反馈必须含「**没验什么**」一节(未覆盖的路径、依赖的
|
||||
假设、不确定的地方);自修过程中改了断言/验收标准必须显式声明理由(改功能让测试过是
|
||||
常规,改测试让功能过需报备);agent 自验对 acceptance,人终验对意图——acceptance
|
||||
可能继承需求理解偏差,两把尺子不可合一
|
||||
|
||||
> 收束:**本体先行,边界一次,操作同语——人指的问题 agent 走得到,人在意的点 agent 读得懂。**
|
||||
> 后半句分两个时间尺度:当下会话由同源路径即时对称(反馈天然绑定双方走过的路径);
|
||||
> 跨会话靠否决理由落账(→ 复盘笔记)积累,人反复在意的维度逐步迁移进可断言规则——
|
||||
> 人裁决区是飞轮推进的前线,不是墙上的洞。
|
||||
|
||||
## 多 AI CLI 协作
|
||||
|
||||
本项目可由多个 AI CLI 协同。交接时把结果总结成 3 条传给下一个:
|
||||
|
||||
@ -549,6 +549,11 @@ pub fn poll_all_repos() -> Result<(usize, usize), String> {
|
||||
&format!("PR 轮询新采集 {pr_ingested} 条事件"), None);
|
||||
}
|
||||
|
||||
// staleness 自知:至少成功拉到一个仓库才算一次有效同步
|
||||
if polled > 0 {
|
||||
crate::db::touch_sync_state(&conn, "flywheel");
|
||||
}
|
||||
|
||||
Ok((polled, ingested))
|
||||
}
|
||||
|
||||
|
||||
@ -564,6 +564,14 @@ fn migrate(conn: &rusqlite::Connection) {
|
||||
CREATE INDEX IF NOT EXISTS idx_pr_events_project ON pr_events(project_id);
|
||||
").expect("create pr_events table");
|
||||
|
||||
// 飞轮同步状态(staleness 自知:派生数据类 MCP 工具据此标注数据新鲜度)
|
||||
conn.execute_batch("
|
||||
CREATE TABLE IF NOT EXISTS sync_state (
|
||||
domain TEXT PRIMARY KEY,
|
||||
synced_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
").expect("create sync_state table");
|
||||
|
||||
// 仪表盘全局快启应用(无项目 FK 约束)
|
||||
conn.execute_batch("
|
||||
CREATE TABLE IF NOT EXISTS global_tools (
|
||||
@ -909,6 +917,26 @@ pub fn conn_with_schema() -> rusqlite::Connection {
|
||||
conn
|
||||
}
|
||||
|
||||
/// 记录某数据域最近一次成功同步时间(upsert)。失败时静默(同步标记不能反噬业务逻辑)
|
||||
pub fn touch_sync_state(conn: &rusqlite::Connection, domain: &str) {
|
||||
let _ = conn.execute(
|
||||
"INSERT INTO sync_state (domain, synced_at) VALUES (?1, datetime('now'))
|
||||
ON CONFLICT(domain) DO UPDATE SET synced_at = datetime('now')",
|
||||
rusqlite::params![domain],
|
||||
);
|
||||
}
|
||||
|
||||
/// 读取某数据域最近同步时间与距今分钟数;无记录返回 None
|
||||
pub fn read_sync_state(conn: &rusqlite::Connection, domain: &str) -> Option<(String, i64)> {
|
||||
conn.query_row(
|
||||
"SELECT synced_at, CAST((julianday('now') - julianday(synced_at)) * 1440 AS INTEGER)
|
||||
FROM sync_state WHERE domain = ?1",
|
||||
rusqlite::params![domain],
|
||||
|r| Ok((r.get(0)?, r.get(1)?)),
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
|
||||
/// 写入运行时日志。失败时静默(不能让日志写入反过来崩溃业务逻辑)
|
||||
pub fn log_event(category: &str, level: &str, message: &str, context: Option<&str>) {
|
||||
let pool = match POOL.get() {
|
||||
@ -946,6 +974,27 @@ mod tests {
|
||||
migrate(&conn);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_state_touch_then_read() {
|
||||
let conn = conn_with_schema();
|
||||
touch_sync_state(&conn, "flywheel");
|
||||
let (at, mins) = read_sync_state(&conn, "flywheel").expect("应有同步记录");
|
||||
assert!(!at.is_empty());
|
||||
assert!(mins >= 0 && mins < 2, "刚 touch 的记录距今应为 0~1 分钟,实际 {mins}");
|
||||
// upsert:重复 touch 不报错、仍只有一行
|
||||
touch_sync_state(&conn, "flywheel");
|
||||
let count: i64 = conn
|
||||
.query_row("SELECT COUNT(*) FROM sync_state WHERE domain='flywheel'", [], |r| r.get(0))
|
||||
.unwrap();
|
||||
assert_eq!(count, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_state_unknown_domain_returns_none() {
|
||||
let conn = conn_with_schema();
|
||||
assert!(read_sync_state(&conn, "nonexistent").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn core_tables_exist() {
|
||||
let conn = conn_with_schema();
|
||||
|
||||
@ -468,10 +468,16 @@ pub async fn tools_call(params: Option<&Value>) -> Value {
|
||||
format!("{icon} PR #{num} [{action}] {title}\n {head} → {base} by {author} @ {at}")
|
||||
})
|
||||
.collect();
|
||||
let fresh_line = match db::read_sync_state(&conn, "flywheel") {
|
||||
Some((at, mins)) => format!(
|
||||
"⏱ 飞轮数据最近同步:{at} UTC(约 {mins} 分钟前)。数据可能滞后——PR 是否已存在以 create_pull_request 返回的 already_exists 为准。\n\n"
|
||||
),
|
||||
None => "⏱ 飞轮数据同步时间未知(尚无同步记录,可先调 poll_now)。\n\n".to_string(),
|
||||
};
|
||||
if rows.is_empty() {
|
||||
Ok(format!("项目 {} 暂无 PR 事件记录", pid))
|
||||
Ok(format!("{fresh_line}项目 {} 暂无 PR 事件记录", pid))
|
||||
} else {
|
||||
Ok(format!("PR 事件(最近 {} 条):\n\n{}", rows.len(), rows.join("\n\n")))
|
||||
Ok(format!("{fresh_line}PR 事件(最近 {} 条):\n\n{}", rows.len(), rows.join("\n\n")))
|
||||
}
|
||||
}
|
||||
"get_commit_metrics" => {
|
||||
@ -509,6 +515,12 @@ pub async fn tools_call(params: Option<&Value>) -> Value {
|
||||
)
|
||||
.unwrap_or(0);
|
||||
let mut out = format!("## 提交飞轮数据(最近 {} 天)\n\n", days);
|
||||
match db::read_sync_state(&conn, "flywheel") {
|
||||
Some((at, mins)) => out.push_str(&format!(
|
||||
"⏱ 飞轮数据最近同步:{at} UTC(约 {mins} 分钟前)\n\n"
|
||||
)),
|
||||
None => out.push_str("⏱ 飞轮数据同步时间未知(尚无同步记录,可先调 poll_now)\n\n"),
|
||||
}
|
||||
out.push_str(&format!("- **总提交数**:{}\n", total));
|
||||
out.push_str(&format!(
|
||||
"- **返工提交**:{} 条({:.0}%)\n",
|
||||
|
||||
@ -151,6 +151,9 @@ async fn handle_push(project_id: &str, body: &Bytes) -> Response {
|
||||
received += 1;
|
||||
}
|
||||
}
|
||||
if received > 0 {
|
||||
db::touch_sync_state(&conn, "flywheel");
|
||||
}
|
||||
log_event(
|
||||
"gitea_webhook",
|
||||
"info",
|
||||
@ -215,6 +218,7 @@ async fn handle_pull_request(project_id: &str, body: &Bytes) -> Response {
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
db::touch_sync_state(&conn, "flywheel");
|
||||
log_event(
|
||||
"gitea_webhook",
|
||||
"info",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user