Compare commits

..

8 Commits

Author SHA1 Message Date
lanrtop
4c7580ccda chore(blueprint): 同步 usage 统计数据
All checks were successful
Push & PR Check / check (push) Successful in 2m27s
2026-08-23 18:08:29 +09:00
lanrtop
2a6d902e5d chore(blueprint): 存档 enterprise 框架重构否决结论 + DevPath 双卡 💭 + 模式库闸门敲响 2026-08-23 16:54:31 +09:00
lanrtop
0d4c2adc54 feat(onboarding): 同源同边界补收束语与需求对称两时间尺度(v1.7.0 内补遗)
「人在意的点 agent 读得懂」补机制脚注使其自洽,不做空头承诺:
- 当下会话:同源路径即时对称(结构直接保证,无需额外机制)
- 跨会话:否决理由落账→复盘笔记→梦核蒸馏,反复在意的维度迁移进可断言规则
- 人裁决区是飞轮推进的前线,不是墙上的洞
- 1.7.0 尚未分发,内容补遗不再升号

Feature-Confirmed: true
2026-08-23 16:41:14 +09:00
lanrtop
08db3c2323 chore(blueprint): 同步 onboarding-pack V2 卡收官 2026-08-23 16:31:42 +09:00
lanrtop
9f468a13a1 feat(onboarding): AGENTS 模板注入「同源同边界 + 操作复刻」设计原则(v1.7.0)
多角度辩证收敛后的 v3.1 外科手术版(真实增量三个半,不重复已有六条):
- 节首总纲:任何功能 = 一个本体 + 两个投影,同源同边界;先定本体后盖投影(原型探索豁免)
- 边界单点实现追加同源推论:人的操作序列 agent 皆可复刻,人报障即复现路径(操作+状态)
- 三分定位启发式(本体→投影→环境),从"定律"降级——crypto.randomUUID 环境层实锤
- human_verify 否决理由值得记录(飞轮原料;采集机制挂 governance-feedback-loop,不空头承诺)
- 炼境自身 AGENTS.md 块内同步 + agents-meta-rules.md 设计草案同步

Feature-Confirmed: true
Rules-Applied: R13
2026-08-23 16:31:30 +09:00
lanrtop
1bb4ce978e chore(blueprint): 沉淀开发侧世界模型透镜 + staleness 卡收官 + notes 档案卡就绪 2026-08-23 15:46:41 +09:00
lanrtop
0a8a9e60bc feat(mcp): 飞轮派生数据工具输出 staleness 标注
世界模型自洽:模型可以过期,不能不知道自己过期。
- 新增 sync_state 表(domain 单行 upsert)+ touch/read 依赖注入函数
- 三个写入点:轮询成功(polled>0)、webhook PR 落库、webhook push 落库
- get_pr_events / get_commit_metrics 输出首行标注最近同步时间与距今分钟数
- get_ci_status 为实时 Gitea API 调用,不在范围
- 实锤依据:get_pr_events 延迟致 /ship 误判无 open PR(enterprise-system 2026-07-28 回传)

Feature-Confirmed: true
Rules-Applied: R05, R06, R07
2026-08-23 15:46:03 +09:00
lanrtop
16473e7260 fix(envoy): 补炼境定位讨论触发标准和 MCP 降级说明
- Step 2 加炼境定位/缺口/演进方向讨论不得漏判警示(enterprise-system 实锤)
- Step 4 加 MCP 不可用时的降级路径(整理文本输出让用户手动转发)
2026-08-23 14:34:17 +09:00
14 changed files with 5034 additions and 11 deletions

View File

@ -6,7 +6,7 @@ description: >
成为每个项目的贴身导师。炼境本身亦被纳入其中, 成为每个项目的贴身导师。炼境本身亦被纳入其中,
形成可自我进化的开发智能闭环。 形成可自我进化的开发智能闭环。
iteration: 1 iteration: 1
updated: 2026-07-04 updated: 2026-08-23
agent_button_carrier: tauri agent_button_carrier: tauri
@ -422,7 +422,8 @@ modules:
area: backend area: backend
status: concept status: concept
progress: 0 progress: 0
note: "老板-员工手册隐喻:用户反馈子项目问题 → 结构化落账 → 梦核蒸馏进规则/模板 → 批量分发 → 飞轮观测生效。三缺口:反馈入口、反馈进梦核高权重输入、接入包批量重分发" note: "老板-员工手册隐喻反馈→落账→梦核蒸馏→批量分发→飞轮观测。2026-08-23 沉淀「开发侧世界模型透镜」三闸门跨项目edges/全局地图/模式库)+ 三投影准入律;📋 notes 档案落地卡就绪(可拆除性唯一硬违规修复)"
updated: 2026-08-23
position: [1250, 650] position: [1250, 650]
- id: mcp-single-server - id: mcp-single-server

View File

@ -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全堵 - ~~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 才会分发到子项目**(模板打包在二进制资源) - 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 资产层=接入包(唯一模式雏形)|地图=单项目蓝图画布(无全局)|可拆除性=资产纯文件 gitnotes 是唯一违规点)。
### 两处判断修正(辩证结论,防后续会话重新推演)
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 拆卡)

View File

@ -55,6 +55,13 @@
> 完成记录2026-07-03能力双投影概念的首次实践。cargo test 全绿;实测验证由 agent 通过 MCP 端点亲自按下这三颗按钮完成。 > 完成记录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 返回 Noneget_pr_events / get_commit_metrics 输出首行含「⏱ 飞轮数据最近同步」cargo test 通过
- 备注世界模型自洽——模型可以过期不能不知道自己过期。实锤get_pr_events 延迟致 /ship 误判无 open PRenterprise-system 2026-07-28 回传。get_ci_status 是实时 Gitea API 调用不在范围内。sync_state 单行 domain='flywheel',轮询成功与 webhook 落库两处 touch
### 💭 能力双投影后续扩展R12 规则化 + 更多按钮) ### 💭 能力双投影后续扩展R12 规则化 + 更多按钮)
- status: concept - status: concept
- 侦察→驻军2026-07-03: agent 走流程验证=侦察智能、贵、一次性验收vitest/cargo test=驻军固化、免费、高频回归agent 验证通过的关键路径顺手固化为测试(接宪章"坑驱动增量"),一次性验收不固化(少而稳>多而脆)。不引入 BDD/spec 框架——acceptance 字段已是人机共读的 spec - 侦察→驻军2026-07-03: agent 走流程验证=侦察智能、贵、一次性验收vitest/cargo test=驻军固化、免费、高频回归agent 验证通过的关键路径顺手固化为测试(接宪章"坑驱动增量"),一次性验收不固化(少而稳>多而脆)。不引入 BDD/spec 框架——acceptance 字段已是人机共读的 spec

View File

@ -160,6 +160,14 @@
- acceptance: [MCP tool] get_diagnostics或 verify_onboarding 检查链)新增「沉默项目」信号:项目近 30 天 commit_metrics 有数据但使者回传list_envoy_returns 同源数据)为 0 → 列出项目名 + commit 数,提示去该项目跑 /envoy近 30 天有回传或无 commit 活动 → 不报 - 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 后置欠账(体系遵守度检查) - 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 【复盘】U1 全托管文件升级通道 + 批量重分发2026-07-15

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,8 @@
回顾本次会话的完整对话,识别有价值的洞察。 回顾本次会话的完整对话,识别有价值的洞察。
跳过:纯代码实现细节、具体 bug 修复、一次性操作记录。 跳过:纯代码实现细节、具体 bug 修复、一次性操作记录。
> ⚠️ **炼境定位讨论不得漏判**:凡涉及「炼境自身定位 / 缺口 / 演进方向 / 与其他工具的对比」的讨论,即便看起来像聊天而非技术实现,**默认视为体系级洞察,列入带回候选清单**。此类内容在历史会话中曾被漏传(判定为聊天),经用户追问才补发。
## Step 3分类每条洞察 ## Step 3分类每条洞察
**前置硬门槛(先于一切分类判断)**:问自己——**任何有经验的工程师是否会提前想到这一点?** **前置硬门槛(先于一切分类判断)**:问自己——**任何有经验的工程师是否会提前想到这一点?**
@ -34,6 +36,8 @@
## Step 4发回炼境 ## Step 4发回炼境
对每条「带回」洞察,单独调用一次 `mcp__lian-jing__append_project_note` 对每条「带回」洞察,单独调用一次 `mcp__lian-jing__append_project_note`
> **MCP 不可用时的降级**:若 `mcp__lian-jing__append_project_note` 报连接错误,重试 1~2 次仍失败,则将所有待回传内容按 Step 4 格式整理成一段文本输出到对话让用户看到并提示「MCP 断连,请复制以上内容到炼境会话手动执行 `/envoy` 回传,或重连后重跑本命令」。
- `project_id`:来自 Step 1 - `project_id`:来自 Step 1
- `content` 格式(严格遵守): - `content` 格式(严格遵守):

View File

@ -138,7 +138,7 @@ docs/templates/ 炼境接入包模板草案(设计层)
完整规则(迭代管理、阻塞处理、复盘笔记等)详见 `.blueprint/CONVENTIONS.md` 完整规则(迭代管理、阻塞处理、复盘笔记等)详见 `.blueprint/CONVENTIONS.md`
<!-- BLUEPRINT_MANAGED_END --> <!-- BLUEPRINT_MANAGED_END -->
<!-- ONBOARDING_MANAGED_START version="1.6.1" --> <!-- ONBOARDING_MANAGED_START version="1.7.0" -->
> ⚠️ 本块由炼境版本化托管,升级时**整块原位覆盖**——项目定制请写到块外块内手改必丢2026-07-15 炼境自身实锤丢失 5 段定制后新增本警示)。 > ⚠️ 本块由炼境版本化托管,升级时**整块原位覆盖**——项目定制请写到块外块内手改必丢2026-07-15 炼境自身实锤丢失 5 段定制后新增本警示)。
## 核心开发约束 ## 核心开发约束
@ -189,10 +189,14 @@ docs/templates/ 炼境接入包模板草案(设计层)
## agent 按钮与验证路径 ## agent 按钮与验证路径
功能的本体是代码层的能力UI 按钮是它给人的投影,**agent 按钮**是给 agent 的投影 功能的本体是代码层的能力UI 按钮是它给人的投影,**agent 按钮**是给 agent 的投影
(可发现 + 可调用 + 有边界的能力声明)。开发任何功能时遵守: (可发现 + 可调用 + 有边界的能力声明)。**任何功能 = 一个本体 + 两个投影,同源同边界**
设计交付时先定本体后盖投影(原型探索不受此序约束,交付前本体归位)。开发任何功能时遵守:
1. **边界单点实现**业务校验只写在能力本体层API/commandUI 只呈现不复制逻辑—— 1. **边界单点实现**业务校验只写在能力本体层API/commandUI 只呈现不复制逻辑——
否则人与 agent 的验证路径会分裂 否则人与 agent 的验证路径会分裂。同源的直接推论:**人的操作序列 agent 皆可复刻**——
人报障即复现路径(操作 + 状态agent 重放至同一状态定位病灶。
三分定位启发式:本体重放正常 → 优先怀疑投影层(接线/渲染/状态同步)→ 再查环境差异
(安全上下文/网络/OS重放失败先怀疑初始状态差异而非否定问题存在
2. **载体就近选择**(本项目的 agent 按钮是什么,按项目类型对号入座): 2. **载体就近选择**(本项目的 agent 按钮是什么,按项目类型对号入座):
| 项目类型 | agent 按钮载体 | | 项目类型 | agent 按钮载体 |
|---------|---------------| |---------|---------------|
@ -214,11 +218,17 @@ docs/templates/ 炼境接入包模板草案(设计层)
- `agent_verify:` — 机器可断言HTTP 状态码、数据库记录、函数返回值stop hook / CI 只验此段 - `agent_verify:` — 机器可断言HTTP 状态码、数据库记录、函数返回值stop hook / CI 只验此段
- `human_verify:` — 需人眼判断视觉效果、拖拽手势、30 秒浏览器终验) - `human_verify:` — 需人眼判断视觉效果、拖拽手势、30 秒浏览器终验)
纯 API / 命令行任务可省略 `human_verify:`UI 拖拽 / 动画 / 视觉类必须拆,否则 stop hook 无法收敛。 纯 API / 命令行任务可省略 `human_verify:`UI 拖拽 / 动画 / 视觉类必须拆,否则 stop hook 无法收敛。
human_verify 的否决理由值得记录——它是把体感转译成可断言规则的原料。
6. **自验报告纪律**:交人终验前的反馈必须含「**没验什么**」一节(未覆盖的路径、依赖的 6. **自验报告纪律**:交人终验前的反馈必须含「**没验什么**」一节(未覆盖的路径、依赖的
假设、不确定的地方);自修过程中改了断言/验收标准必须显式声明理由(改功能让测试过是 假设、不确定的地方);自修过程中改了断言/验收标准必须显式声明理由(改功能让测试过是
常规改测试让功能过需报备agent 自验对 acceptance人终验对意图——acceptance 常规改测试让功能过需报备agent 自验对 acceptance人终验对意图——acceptance
可能继承需求理解偏差,两把尺子不可合一 可能继承需求理解偏差,两把尺子不可合一
> 收束:**本体先行,边界一次,操作同语——人指的问题 agent 走得到,人在意的点 agent 读得懂。**
> 后半句分两个时间尺度:当下会话由同源路径即时对称(反馈天然绑定双方走过的路径);
> 跨会话靠否决理由落账(→ 复盘笔记)积累,人反复在意的维度逐步迁移进可断言规则——
> 人裁决区是飞轮推进的前线,不是墙上的洞。
## 多 AI CLI 协作 ## 多 AI CLI 协作
本项目可由多个 AI CLI 协同。交接时把结果总结成 3 条传给下一个: 本项目可由多个 AI CLI 协同。交接时把结果总结成 3 条传给下一个:

View File

@ -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 写法规范
acceptance 是 agent 自验的唯一判断依据,必须是**可执行断言**,不能是描述性语句: acceptance 是 agent 自验的唯一判断依据,必须是**可执行断言**,不能是描述性语句:

View File

@ -16,6 +16,8 @@
回顾本次会话的完整对话,识别有价值的洞察。 回顾本次会话的完整对话,识别有价值的洞察。
跳过:纯代码实现细节、具体 bug 修复、一次性操作记录。 跳过:纯代码实现细节、具体 bug 修复、一次性操作记录。
> ⚠️ **炼境定位讨论不得漏判**:凡涉及「炼境自身定位 / 缺口 / 演进方向 / 与其他工具的对比」的讨论,即便看起来像聊天而非技术实现,**默认视为体系级洞察,列入带回候选清单**。此类内容在历史会话中曾被漏传(判定为聊天),经用户追问才补发。
## Step 3分类每条洞察 ## Step 3分类每条洞察
**前置硬门槛(先于一切分类判断)**:问自己——**任何有经验的工程师是否会提前想到这一点?** **前置硬门槛(先于一切分类判断)**:问自己——**任何有经验的工程师是否会提前想到这一点?**
@ -36,6 +38,8 @@
## Step 4发回炼境 ## Step 4发回炼境
对每条「带回」洞察,单独调用一次 `mcp__lian-jing__append_project_note` 对每条「带回」洞察,单独调用一次 `mcp__lian-jing__append_project_note`
> **MCP 不可用时的降级**:若 `mcp__lian-jing__append_project_note` 报连接错误,重试 1~2 次仍失败,则将所有待回传内容按 Step 4 格式整理成一段文本输出到对话让用户看到并提示「MCP 断连,请复制以上内容到炼境会话手动执行 `/envoy` 回传,或重连后重跑本命令」。
- `project_id`:来自 Step 1 - `project_id`:来自 Step 1
- `content` 格式(严格遵守): - `content` 格式(严格遵守):

View File

@ -18,7 +18,7 @@
<!-- TODO: 列出 README / ARCHITECTURE.md / 其他关键文档及用途。 --> <!-- TODO: 列出 README / ARCHITECTURE.md / 其他关键文档及用途。 -->
<!-- ONBOARDING_MANAGED_START version="1.6.1" --> <!-- ONBOARDING_MANAGED_START version="1.7.0" -->
> ⚠️ 本块由炼境版本化托管,升级时**整块原位覆盖**——项目定制请写到块外块内手改必丢2026-07-15 炼境自身实锤丢失 5 段定制后新增本警示)。 > ⚠️ 本块由炼境版本化托管,升级时**整块原位覆盖**——项目定制请写到块外块内手改必丢2026-07-15 炼境自身实锤丢失 5 段定制后新增本警示)。
## 核心开发约束 ## 核心开发约束
@ -69,10 +69,14 @@
## agent 按钮与验证路径 ## agent 按钮与验证路径
功能的本体是代码层的能力UI 按钮是它给人的投影,**agent 按钮**是给 agent 的投影 功能的本体是代码层的能力UI 按钮是它给人的投影,**agent 按钮**是给 agent 的投影
(可发现 + 可调用 + 有边界的能力声明)。开发任何功能时遵守: (可发现 + 可调用 + 有边界的能力声明)。**任何功能 = 一个本体 + 两个投影,同源同边界**
设计交付时先定本体后盖投影(原型探索不受此序约束,交付前本体归位)。开发任何功能时遵守:
1. **边界单点实现**业务校验只写在能力本体层API/commandUI 只呈现不复制逻辑—— 1. **边界单点实现**业务校验只写在能力本体层API/commandUI 只呈现不复制逻辑——
否则人与 agent 的验证路径会分裂 否则人与 agent 的验证路径会分裂。同源的直接推论:**人的操作序列 agent 皆可复刻**——
人报障即复现路径(操作 + 状态agent 重放至同一状态定位病灶。
三分定位启发式:本体重放正常 → 优先怀疑投影层(接线/渲染/状态同步)→ 再查环境差异
(安全上下文/网络/OS重放失败先怀疑初始状态差异而非否定问题存在
2. **载体就近选择**(本项目的 agent 按钮是什么,按项目类型对号入座): 2. **载体就近选择**(本项目的 agent 按钮是什么,按项目类型对号入座):
| 项目类型 | agent 按钮载体 | | 项目类型 | agent 按钮载体 |
|---------|---------------| |---------|---------------|
@ -94,11 +98,17 @@
- `agent_verify:` — 机器可断言HTTP 状态码、数据库记录、函数返回值stop hook / CI 只验此段 - `agent_verify:` — 机器可断言HTTP 状态码、数据库记录、函数返回值stop hook / CI 只验此段
- `human_verify:` — 需人眼判断视觉效果、拖拽手势、30 秒浏览器终验) - `human_verify:` — 需人眼判断视觉效果、拖拽手势、30 秒浏览器终验)
纯 API / 命令行任务可省略 `human_verify:`UI 拖拽 / 动画 / 视觉类必须拆,否则 stop hook 无法收敛。 纯 API / 命令行任务可省略 `human_verify:`UI 拖拽 / 动画 / 视觉类必须拆,否则 stop hook 无法收敛。
human_verify 的否决理由值得记录——它是把体感转译成可断言规则的原料。
6. **自验报告纪律**:交人终验前的反馈必须含「**没验什么**」一节(未覆盖的路径、依赖的 6. **自验报告纪律**:交人终验前的反馈必须含「**没验什么**」一节(未覆盖的路径、依赖的
假设、不确定的地方);自修过程中改了断言/验收标准必须显式声明理由(改功能让测试过是 假设、不确定的地方);自修过程中改了断言/验收标准必须显式声明理由(改功能让测试过是
常规改测试让功能过需报备agent 自验对 acceptance人终验对意图——acceptance 常规改测试让功能过需报备agent 自验对 acceptance人终验对意图——acceptance
可能继承需求理解偏差,两把尺子不可合一 可能继承需求理解偏差,两把尺子不可合一
> 收束:**本体先行,边界一次,操作同语——人指的问题 agent 走得到,人在意的点 agent 读得懂。**
> 后半句分两个时间尺度:当下会话由同源路径即时对称(反馈天然绑定双方走过的路径);
> 跨会话靠否决理由落账(→ 复盘笔记)积累,人反复在意的维度逐步迁移进可断言规则——
> 人裁决区是飞轮推进的前线,不是墙上的洞。
## 多 AI CLI 协作 ## 多 AI CLI 协作
本项目可由多个 AI CLI 协同。交接时把结果总结成 3 条传给下一个: 本项目可由多个 AI CLI 协同。交接时把结果总结成 3 条传给下一个:

View File

@ -549,6 +549,11 @@ pub fn poll_all_repos() -> Result<(usize, usize), String> {
&format!("PR 轮询新采集 {pr_ingested} 条事件"), None); &format!("PR 轮询新采集 {pr_ingested} 条事件"), None);
} }
// staleness 自知:至少成功拉到一个仓库才算一次有效同步
if polled > 0 {
crate::db::touch_sync_state(&conn, "flywheel");
}
Ok((polled, ingested)) Ok((polled, ingested))
} }

View File

@ -564,6 +564,14 @@ fn migrate(conn: &rusqlite::Connection) {
CREATE INDEX IF NOT EXISTS idx_pr_events_project ON pr_events(project_id); CREATE INDEX IF NOT EXISTS idx_pr_events_project ON pr_events(project_id);
").expect("create pr_events table"); ").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 约束) // 仪表盘全局快启应用(无项目 FK 约束)
conn.execute_batch(" conn.execute_batch("
CREATE TABLE IF NOT EXISTS global_tools ( CREATE TABLE IF NOT EXISTS global_tools (
@ -909,6 +917,26 @@ pub fn conn_with_schema() -> rusqlite::Connection {
conn 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>) { pub fn log_event(category: &str, level: &str, message: &str, context: Option<&str>) {
let pool = match POOL.get() { let pool = match POOL.get() {
@ -946,6 +974,27 @@ mod tests {
migrate(&conn); 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] #[test]
fn core_tables_exist() { fn core_tables_exist() {
let conn = conn_with_schema(); let conn = conn_with_schema();

View File

@ -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}") format!("{icon} PR #{num} [{action}] {title}\n {head}{base} by {author} @ {at}")
}) })
.collect(); .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() { if rows.is_empty() {
Ok(format!("项目 {} 暂无 PR 事件记录", pid)) Ok(format!("{fresh_line}项目 {} 暂无 PR 事件记录", pid))
} else { } 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" => { "get_commit_metrics" => {
@ -509,6 +515,12 @@ pub async fn tools_call(params: Option<&Value>) -> Value {
) )
.unwrap_or(0); .unwrap_or(0);
let mut out = format!("## 提交飞轮数据(最近 {} 天)\n\n", days); 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!("- **总提交数**{}\n", total));
out.push_str(&format!( out.push_str(&format!(
"- **返工提交**{} 条({:.0}%\n", "- **返工提交**{} 条({:.0}%\n",

View File

@ -151,6 +151,9 @@ async fn handle_push(project_id: &str, body: &Bytes) -> Response {
received += 1; received += 1;
} }
} }
if received > 0 {
db::touch_sync_state(&conn, "flywheel");
}
log_event( log_event(
"gitea_webhook", "gitea_webhook",
"info", "info",
@ -215,6 +218,7 @@ async fn handle_pull_request(project_id: &str, body: &Bytes) -> Response {
match result { match result {
Ok(_) => { Ok(_) => {
db::touch_sync_state(&conn, "flywheel");
log_event( log_event(
"gitea_webhook", "gitea_webhook",
"info", "info",