新增 AutoRDO 需求清洗工作台与消息中枢,迭代 OneOS V2 设计规范及租赁合同/工作台/车辆等原型,同步云效技能与导航注册;并归档一批 legacy 原型快照。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
王冕
2026-07-28 15:50:35 +08:00
parent b14425da5a
commit 5d51a6bf7a
1393 changed files with 488042 additions and 10046 deletions

View File

@@ -0,0 +1,83 @@
---
name: AutoRDO
description: >-
AutoRDO (Requirement Description Optimization): cleans fragmented chat logs,
voice transcripts, oral notes, and feedback ledgers into written title and description;
auto-detects 类型/优先级/标签/提交部门/提交人 from content; maps OneOS modules via oneos-domain.md;
splits multi-line into multiple results; if any 待确认 exists, MUST switch to Plan mode
for choice-based confirmation. Does not change Yunxiao status or create tasks.
Pair with YunxiaoPMapp for cloud write; never load yunxiao-requirement-lifecycle.
---
# AutoRDO
**Requirement Description Optimization**(需求描述优化)。
将碎片化、通俗化文字(聊天/录音/反馈台账)在**保留原意**前提下拆解为**标题、描述**,并**自动识别**类型、优先级、标签、提交部门、提交人,供入库写入云效需求。
多行/多条独立诉求 → **自动拆成多份**转译结果。
**强制**:清洗结果中**只要存在任意「待确认」**Agent **必须立刻** `SwitchMode`**plan**,逐条用选择题消解;**无需**用户再说「确认待确认」。无待确认则可直接交定稿。
## 边界(强制)
| 做 | 不做 |
|---|---|
| 提炼标题与书面描述;自动识别类型/优先级/标签/提交部门/提交人 | 改云效状态 / 建任务 / **直接**打云效标签 |
| 多行/多条 → 多份转译结果 | 写成完整 AutoPRD / 臆造业务结论 |
| 有待确认 → 强制 Plan 逐条确认 | 停在初稿等口令;把猜测写入定稿 |
| 去除描述**结尾句号** | 加载 `yunxiao-requirement-lifecycle` |
云效建单与打标由 **`$YunxiaoPMapp`** 负责;本 Skill 只出清洗稿与**推荐元数据**。
## 何时使用
- 口令含 `AutoRDO` / `清洗聊天` / `录音整理` / `原始诉求`
- 粘贴反馈台账(含部门/优先级/模块列)或口述碎片
- YunxiaoPMapp「记录需求」前必须先跑本 Skill材料为碎片/台账时)
## 输入
- 聊天、会议速记、口述、录音转写
- **多行/台账**含反馈人、所属部门、业务模块、优先级、PC或移动端等列时优先采信列值
- 确认阶段补充文字
## 处理规则
**强制前置**ONE-OS 材料先 Read [references/oneos-domain.md](references/oneos-domain.md),元数据规则见 [references/meta-fields.md](references/meta-fields.md),再按 [references/rules.md](references/rules.md) 执行。
1. **多条拆解** → 每条独立成稿
2. **OneOS 对齐** → 模块/部门标准名
3. **元数据识别** → 类型、优先级、标签、提交部门、提交人(显式列 > 正文标记 > 语义推断;不确定 → 待确认)
4. **标题 + 描述转译** → 去口语、去结尾句号
5. **有待确认 → 强制 Plan** → 见 [references/confirm-pending.md](references/confirm-pending.md)
## 输出
```markdown
## 原始诉求AutoRDO
**标题**<清晰标题>
**类型**:【新增】|【优化】
**优先级**P1-高|P2-中|P3-低
**标签**<标准模块>[, PC端|小程序]
**提交部门**<标准部门名或空>
**提交人**<姓名或空>
**描述**
<转译正文;无结尾句号>
反馈:<有则附日期/禅道/状态/端>
待确认:
-
```
多条时先写「共 N 条」,再 `### 1``### N`
交 YunxiaoPMapp 示例:`记录需求:标题=…;类型=…;优先级=…;标签=…;提交部门=…;提交人=…;描述=…`
## 口令
```text
AutoRDO<粘贴聊天或台账行>
AutoRDO录音转写如下 …
按下列补充消解待确认:
<补充说明>
```

View File

@@ -0,0 +1,4 @@
interface:
display_name: "AutoRDO"
short_description: "清洗诉求并识别类型优先级标签部门提交人"
default_prompt: "按 AutoRDO 清洗:先读 oneos-domain.md 与 meta-fields.md多行拆多条出标题+描述+类型/优先级/标签/提交部门/提交人。有待确认则同轮强制切 Plan 用选择题消解;不改云效、不直接打标、不贴词典全文。"

View File

@@ -0,0 +1,126 @@
# AutoRDO · 待确认逐条 Plan 确认
## 目标
清洗稿中的「待确认」经产品经理**逐条人工确认**后,回填进标题/描述,得到可交 YunxiaoPMapp 的定稿。
确认过程**优先选择题**;选项用 [oneos-domain.md](oneos-domain.md) 辅助生成;也支持用补充说明/需求描述文字直接消解待确认点。
## 何时进入(强制)
```text
清洗初稿产出后:
若任一需求含「待确认」→ 同轮必须 SwitchMode → plan
若全部无待确认 → 不必进 Plan初稿即定稿
```
- **触发条件只有一条**:存在待确认(单条或多条中任意一点)
- **禁止**要求用户再说「确认待确认」「开始确认」才进 Plan
- 用户在 Plan 中可用选择题作答,也可粘贴补充说明消解
**不进 Plan 的唯一情况**:清洗结果中没有任何「待确认」条目。
## Plan 门禁(强制)
1. 清洗初稿写出后(可先展示初稿摘要),**立刻** `SwitchMode`**plan**,说明:存在待确认,须逐条确认后再回填定稿;本阶段仍**不写云效**
2. Plan 列出:待确认的**需求条号**、每条下的待确认点清单、推荐确认方式(选择题 / 文字补充)
3. **用户确认 / 批准 Plan / 「执行」之前**:禁止把未确认内容写进定稿描述
4. 批准后:按条推进确认 → 回填 → 输出定稿
## 逐条确认顺序
```text
需求 1 的待确认点 1 → 点 2 → … → 需求 1 定稿片段
需求 2 的待确认点 1 → …
全部完成后输出「已确认定稿」全集
```
- **一次只推进一个待确认点**(或同一点下的一组互斥选项),避免一屏堆十几个问题
- 多条需求时Plan 清单可注明建议从第 1 条起;用户可指定跳过或改序
- 某条无「待确认」→ 跳过,保留初稿即可
## 确认方式(优先选择)
每个待确认点按下列优先级出题:
| 优先级 | 方式 | 适用 |
|---|---|---|
| 1 | **选择题**25 个互斥选项 + 可选「其他/我补充」) | 模块归属、部门名称、类型/优先级、是否/范围、枚举字段、拆条边界等 |
| 2 | **多选** | 明确可多选的范围如适用端PC+H5 |
| 3 | **文字补充** | 无法枚举、需自由描述字段清单/规则细节时 |
### 选项如何用 OneOS 词典生成
先 Read `oneos-domain.md`,再出选项:
- **模块名不清**:候选 = 词典中相关条线的标准模块名(如还车应结款 / 违章管理 / 还车管理),勿自造模块
- **部门/角色口语**:候选 = 第 1 节标准名(业管→业务管理组,安全小组→安全部 等)+「保持单据原文分区名」
- **跨条线联动**:选项写清主责模块 vs 联动对象;标题只挂主责,联动写描述
- **故事点细节**:仅当材料或用户补充已暗示时,才把词典闭环中的合理分支列为选项;**禁止**把未提及的故事点细节默认选中
每题结构建议:
```text
【需求 n · 待确认 k】<待确认原文>
依据词典,请选择:
A. …
B. …
C. …
D. 其他(请补充一句)
也可用一段需求描述直接回答本点
```
## 用需求描述补充
用户可用以下任一方式消解待确认,**不必**每题都点选:
- 粘贴一段补充说明 / 功能规则 / 字段清单
- 回复「按下列描述确认:…」
- 对某一待确认点直接写答案句
Agent 须:
1. 将补充文字**映射**到对应待确认点(可一次消解多点)
2. 写入该条**描述**(书面化、去结尾句号),从「待确认」列表**移除已消解项**
3. 补充仍含糊的部分 → 保留或新开「待确认」,继续选择题
4. **不**把补充里未说的内容脑补进去
## 回填定稿规则
确认完成后,对该条输出「已确认」版本:
```markdown
### n已确认
## 原始诉求AutoRDO
**标题**:…
**描述**
<初稿 + 已确认信息合并;无结尾句号>
待确认:
- (无则写「无」或省略本段)
```
- 标题若因模块/动作确认而需微调,可改,并在确认回合说明改了什么
- 未确认点**不得**假装已确认;可标「本条暂缓,待确认仍保留」
- 全部条完成后,给总览:已确认条数 / 仍含待确认条数
## 口令
```text
AutoRDO<材料> → 有待确认则自动进 Plan
按下列补充消解待确认:
<粘贴补充说明>
第 6 条待确认选 A第 7 条补充:字段非必填,计入应补汇总
```
(「确认待确认」等口令**不再作为**进 Plan 的前置条件;有待确认即强制进。)
## 不做
- 确认阶段仍不改云效、不建任务
- 不把 `oneos-domain.md` 全文贴进定稿
- 不跳过 Plan 直接把「猜的答案」写进描述
- 不等用户额外口令才进 Plan有待确认必须进

View File

@@ -0,0 +1,96 @@
# AutoRDO · 元数据自动识别
从粘贴内容(台账表格行、聊天、口述)自动识别下列字段,写入每条原始诉求输出;**不**直接改云效打标(打标由 YunxiaoPMapp 执行)。
## 输出字段
| 字段 | 说明 | 无依据时 |
|---|---|---|
| **类型** | `【新增】` / `【优化】`(与云效标题前缀一致) | 默认 `【优化】`,并列入待确认 |
| **优先级** | `P1-高` / `P2-中` / `P3-低` | 默认 `P2-中`,高不确定则待确认 |
| **标签** | 主模块标签(对齐 `oneos-domain.md` 标准模块名);可附端标签 `PC端` / `小程序` | 仅模块不确定则待确认 |
| **提交部门** | 映射到词典标准部门名 | 材料无部门且无法推断 → 待确认或空 |
| **提交人** | 反馈人/用户姓名 | 材料无人名 → 空(不臆造) |
## 识别优先级
```text
1. 显式列/字段反馈台账优先级、所属部门、反馈方、业务模块、PC或移动端…
2. 正文中的明确标记P1、【优化】、@某人、部门署名)
3. 语义推断(用词 + oneos-domain 模块/部门)
4. 仍不确定 → 待确认(选择题),禁止假装已确认
```
## 类型(【新增】/【优化】)
| 信号 | 类型 |
|---|---|
| 新增、增加、支持、允许、增加列/字段/入口、批量导入(首次能力) | 【新增】 |
| 优化、调整、修改、放开、更清晰、重构、移动至、改由、精确到、兼容 | 【优化】 |
| 台账/口令已写 `【新增】`/`【优化】` | 以显式为准 |
| 同时含新增与优化语义 | 以**主诉求**定类型;次要点写在描述 |
标题可带类型前缀供入库:`【优化】交车管理:…`;若用户只要裸标题,类型仍单独输出字段。
## 优先级
| 信号 | 优先级 |
|---|---|
| 列值 `P1-高` / `P1` / 紧急、阻塞、无法办理、P1 | `P1-高` |
| 列值 `P2-中` / `P2` | `P2-中` |
| 列值 `P3-低` / `P3` / 文案、置灰、体验微调 | `P3-低` |
| 无信号 | 默认 `P2-中` |
## 标签
1. **主标签** = 归属标准模块名(`oneos-domain.md`),如 `还车应结款``违章管理``交车管理`
2. 台账「业务模块」列优先;口语映射到标准名(验车管理→验车入库,调拨管理→车辆调拨)
3. **端标签**(可选,可多选):材料含 `PC端`/`小程序`/`PC及小程序` 时写入
4. 「其他」「全局优化」「小程序审批中心」等非模块名:主标签用最贴近模块或 `系统全局`;勿发明云效不存在的随意标签名
5. 输出格式:逗号分隔,如 `还车应结款, PC端`
## 提交部门
| 材料常见写法 | 标准输出 |
|---|---|
| 业务管理部、业管、业务管理 | 业务管理组 |
| 运维部、运维 | 运维部 |
| 数智中心、数智、信息化 | 数智部 |
| 安全部、安全 | 安全部 |
| 财务部、财务 | 财务部 |
| 法务部、法务 | 法务部 |
| 采购部/采购组 | 按词典区分输出 |
台账「所属部门」列优先;聊天中「我们运维…」可推断,低置信度则待确认。
## 提交人
- 台账「反馈方/用户」「反馈人」列 → 原样作为提交人
- 聊天 @姓名、署名「张三:」→ 取该名
- 多人联合反馈 → 取主反馈人(首列/首个署名);其余可写描述附注
- **禁止**用当前对话用户名冒充提交人(除非材料写明)
## 与描述附注的关系
- **结构化字段**(类型/优先级/标签/提交部门/提交人)单独成行,供 YunxiaoPMapp 建单口令复用
- 禅道编号、处理状态、反馈日期等 → 可放描述末行「反馈:…」附注,不升格为强制字段
## 输出模板(每条)
```markdown
## 原始诉求AutoRDO
**标题**<清晰标题;可选带【新增】/【优化】前缀>
**类型**:【新增】|【优化】
**优先级**P1-高|P2-中|P3-低
**标签**<模块>[, PC端|小程序]
**提交部门**<标准部门名或空>
**提交人**<姓名或空>
**描述**
<转译正文;无结尾句号>
反馈:<日期 · 原文部门 · 状态 · 禅道号 · 端 …>(有则写)
待确认:
-
```

View File

@@ -0,0 +1,399 @@
# ONE-OS 业务领域词典(供 AutoRDO 对齐)
> 来源:业务条线说明原型 `lease-business-line-overview`
> 用途:清洗标题/描述时,优先用下列**标准模块名、部门名、闭环表述**对齐,避免口语臆造模块或错挂条线。
> 系统定位1 套系统 · 5 大业务条线闭环 · 3 大数据底座 · 演进方向为业财一体
> **强制**:本文件只用于理解与用词对齐;**禁止**把本词典全文贴进云效描述或 AutoRDO 输出稿。
---
## 0. 系统总览
| 维度 | 口径 |
|---|---|
| 平台名 | ONE-OS亦写作 OneOS |
| 五大业务条线 | 租赁 · 能源 · 运维 · 安全 · 物流 |
| 三大数据底座 | 车辆资产运营情况 · 各业务条线盈亏情况 · 里程调度情况 |
| 现阶段 | 业务驱动 · 财务手工维护(收款/付款/核销多人工) |
| 演进方向 | 业财闭环一体化(打通财务 YS「收款记录」「付款记录」与业务台账双向回写 |
**标题提炼提示**:口述涉及合同/台账/交还车/氢费/证照/调度时,先归入对应条线再落模块名;跨条线联动(如还车应结款联动违章事故)在描述中写明联动对象,标题以主责模块为准。
---
## 1. 业务部门 / 角色词典(标准用词)
清洗时统一下列名称;同义口语请映射到标准名。
| 标准名称 | 常见口语/别称 | 主要出现条线 |
|---|---|---|
| 业务管理组 | 业管、业务管理 | 租赁、运维、安全、物流 |
| 业务管理组-能源部 | 能源组、业管能源、业务管理部-能源组 | 能源、租赁还车 |
| 业务服务组 | 业务服务 | 物流 |
| 业务员 | 业务 | 租赁 |
| 调度岗 | 调度 | 物流 |
| 法务部 | 法务 | 租赁、运维采购合同 |
| 财务部 | 财务 | 租赁评级、能源账户、运维付款/维保、安全违章事故、物流台账 |
| 安全部 | 安全 | 租赁评级、证照、安全条线 |
| 运维部 | 运维、区域操作员 | 运维全链路、交还车、租赁提车后交车 |
| 采购部 | 采购 | 能源加氢站、运维采购合同/验车 |
| 采购组 | 采购组 | 供应商管理(能源/运维) |
| 数智部 | 数智、信息化 | 合同模板电子化、能源扩展 |
| 董事长 | 老板、总 | 非标合同、资产出售过户报废确认 |
| 司机 | 提车司机、内部司机 | 交车培训、故障、安全培训 |
| 加氢站 / 签约加氢站 | 站点、站方 | 能源 |
**组织边界提示**
- 「采购组」侧重供应商主数据;「采购部」侧重站点管理与采购/三方租赁合同。
- 「业务管理组」与「业务管理组-能源部」勿混用;氢费、加氢对账默认能源部。
- 物流调度明确:**非 TMS**,不做配载与承运商调度。
---
## 2. 功能模块总表(按条线)
### 2.1 租赁业务条线6 模块 · 全链路闭环)
**条线闭环**:客户评级决定是否可签 → 标准模板支撑签约 → 租赁合同进入履约 → 提车应收对齐后交车 → 台账承接租期账单 → 还车应结款会签归档。
| 步 | 模块名 | 一句话定位 | 责任部门 |
|---|---|---|---|
| 1 | 客户管理 | 准入评级 · 决定能否签约、走哪条流程 | 业务管理组、法务部、财务部、安全部 |
| 2 | 标准合同管理 | 模板配置 · 支撑电子合同一键发起 | 法务部、数智部 |
| 3 | 租赁合同 | 签约发起 · 标准 / 非标 / 禁止三条路径 | 业务员、法务部 |
| 4 | 提车应收款 | 应收生成 · 实收对齐 · 触发交车 | 业务员、法务部、业务管理组、运维部 |
| 5 | 租赁业务台账 | 交车后账单 · 周期收费与实收延续 | 运维部、业务员、业务管理组 |
| 6 | 还车应结款 | 还车结算 · 多部门会签 · 归档闭环 | 业务管理组、安全部、运维部、业务管理组-能源部 |
**关键结果标签(客户管理)**:可标准签约 · 可签·走非标 · 禁止签约·高风险
---
### 2.2 能源业务条线6 模块 · 业财闭环)
**条线闭环**:供应商主数据支撑站点绑定 → 签约站账号与订单主动上报 → 非签约站氢费补录对账 → 客户对账单关联收款 → 加氢记录标记已付款 → 成熟后向采购端与司机端延伸。
| 步 | 模块名 | 一句话定位 | 责任部门 |
|---|---|---|---|
| 1 | 供应商管理 | 加氢/充电站供应商 · 站点绑定与业财直连 | 采购组、财务部 |
| 2 | 加氢站管理 | 签约站 / 非签约站 · 账号、余额与价格 | 采购部、加氢站 |
| 3 | 加氢订单 | 主动上报 · PLC 自动采集 · 预约接单 | 签约加氢站、业务管理组-能源部 |
| 4 | 车辆氢费明细 | 非签约站补录 · 对账归档 · 余额关联 | 业务管理组-能源部 |
| 5 | 氢费账户 | 客户预付款 · 对账单 · 业财收款闭环 | 业务管理组-能源部、财务部 |
| 6 | 扩展规划 | 上游采购 · 下游司机服务 | 采购部、业务管理组-能源部、数智部 |
---
### 2.3 运维管理条线15 模块)
**主线main**:验车入库 → 上牌 → 证照 → 备车 → 交车 → 还车 → 出售/过户/报废出库
**并行能力support**:供应商、采购合同、替换车、故障、年审、维保、异动、调拨(无严格先后)
**条线闭环**:供应商与采购合同入库 → 上牌证照与备车整备 → 交车/替换/还车闭环 → 故障与年审维保 → 异动调拨 → 出售/过户/报废审批出库。
| 步 | 模块名 | 轨道 | 一句话定位 | 责任部门 |
|---|---|---|---|---|
| 1 | 供应商管理 | support | 整车厂 / 三方租赁 · 付款底座 | 采购组、财务部 |
| 2 | 车辆采购 / 三方租赁合同 | support | 车型数量 · 付款关联 · 验车任务 | 采购部、法务部、财务部 |
| 3 | 验车入库 | main | 采购 / 三方来源 · 验完自动入库 | 运维部、采购部 |
| 4 | 车辆上牌 | main | 车架号入库 · 完成牌证登记 | 运维部 |
| 5 | 证照管理 | main | 一车一档 · 到期待办推送 | 运维部、安全部 |
| 6 | 备车管理 | main | 交车前整备 · 随时可交付 | 运维部 |
| 7 | 交车管理 | main | 司机培训留痕 · 区域派单 · OCR 比对 · 电子签 | 运维部、业务管理组、司机 |
| 8 | 替换车管理 | support | 临时 / 永久替换 · 费用自动核算 | 运维部、业务管理组 |
| 9 | 还车管理 | main | 区域派单 · 费用自动计算 · 电子签 | 运维部、业务管理组 |
| 10 | 故障管理 | support | AI 助手 + 人工 · 证据链归档 | 运维部、司机 |
| 11 | 年审记录 | support | 提前 3 个月 · OCR 刷新证照 | 运维部 |
| 12 | 维修与保养记录 | support | 费用汇总 · 业财一体 · 盈亏核算 | 运维部、财务部 |
| 13 | 车辆异动 | support | 出库维修 / 年审 / 保养 · 成本归集 | 运维部 |
| 14 | 车辆调拨 | support | 跨区调拨 · 运维权转移 | 运维部、业务管理组 |
| 15 | 车辆出售、过户、报废 | main | 资产变更审批 · 过程留痕 · 自动出库 | 运维部、董事长、财务部 |
---
### 2.4 安全管理条线6 模块 · 安全闭环)
**条线闭环**:司机信息与证照 → 定期培训与资料库学习 → 违规记录关联评级 → 违章/事故登记 → 联动还车应结款与代处理费用。
| 步 | 模块名 | 一句话定位 | 责任部门 |
|---|---|---|---|
| 1 | 司机管理 | 物流内部司机 · 信息证照一体 | 安全部、业务管理组 |
| 2 | 内部司机培训 | 定期安全培训 · 证据链留痕 | 安全部、司机 |
| 3 | 安全培训资料库 | 资料上传 · APP / 小程序学习 | 安全部、司机 |
| 4 | 违规记录 | 司机违规 · 关联评级 | 安全部、业务管理组 |
| 5 | 违章管理 | 分值罚款 · 还车联动 · 代处理 | 安全部、财务部、业务管理组 |
| 6 | 事故管理 | 权责划分 · 保险赔付 · 还车联动 | 安全部、财务部、业务管理组 |
---
### 2.5 物流业务条线3 模块 · 经营闭环)
**条线闭环**:物流合同生效 → 轻量调度派车(交车后可办结)→ 办结自动生成物流业务明细 → 汇总盈亏 → 汇集项目盈亏表 → 演进关联收款记录完成业财闭环。
| 步 | 模块名 | 一句话定位 | 责任部门 |
|---|---|---|---|
| 1 | 物流合同 | 关键信息录入 · 业务确认生效 · 可派车 | 业务管理组、业务服务组 |
| 2 | 调度任务 | 轻量派车 · 交还车校验 · 办结出车 | 业务服务组、调度岗、运维部 |
| 3 | 物流台账 | 任务自动生成 · 补录导入 · 盈亏核算 | 业务服务组、财务部 |
---
### 2.6 三大数据底座(管理决策层,非业务条线)
| 底座 | 看什么 | 主要数据来源条线 |
|---|---|---|
| 车辆资产运营情况 | 规模 · 结构 · 健康度 · 品牌型号出勤率下钻省市 | 运维、车辆管理、证照/保险、交车/备车 |
| 各业务条线盈亏情况 | 收入 · 成本 · 利润(条线/项目/单车) | 租赁台账、物流台账、氢费账户、收款、维保/事故/违章 |
| 里程调度情况 | 里程补贴 · 客户履约 · 智能替换与运维干预 | 车机/GPS/人工里程、客户里程约定、替换车、运维干预 |
---
## 3. 流程闭环速查(端到端一句话)
| 条线 | 闭环一句话 |
|---|---|
| 租赁 | 客户 → 模板 → 签约 → 提车应收 → 交车 → 台账账单 → 还车应结款归档 |
| 能源 | 供应商 → 加氢站 → 订单采集 → 氢费明细 → 客户账户收款 → 记录已付款 |
| 运维 | 采购/验车入库 → 牌证备车 → 交还车 → 维保故障 → 异动调拨 → 处置出库 |
| 安全 | 司机档案 → 培训资料 → 违规评级 → 违章事故 → 还车应结款费用 |
| 物流 | 合同生效 → 调度派车办结 → 台账明细/盈亏 →(演进)收款业财闭环 |
| 系统级 | 五条线业务闭环 → 三大数据底座决策 → 打通财务 YS 业财一体 |
**高频跨模块联动(写描述时勿漏)**
- 租赁签约路径依赖**客户管理**评级(标准 / 非标 / 禁止)
- **提车应收**对齐后触发运维**交车**;交车成功生成**租赁业务台账**
- **还车管理**完成后生成**还车应结款**;安全**违章/事故**费用写入应结项
- 运维**采购/三方租赁合同**自动生成**验车入库**任务
- 物流**调度办结**须车辆已**交车**;办结自动写**物流台账**
- 能源签约站**加氢订单**与非签约站**氢费明细**统一进入**氢费账户**对账收款
---
## 4. 故事点(按模块:起点 → 怎么运作 → 闭环)
> 结构对齐页面「起点 / 怎么运作 / 闭环」。标题用「模块名 + 核心动作」;描述保留谁发起、关键规则、闭环结果,不升格成完整 PRD。
> 下列为各模块业务事实摘要,用于**识别归属与用词**;材料未提及的细节**不得**脑补进描述。
### 4.1 租赁
#### 客户管理
- **起点**:业务管理组维护客户基础信息,作为后续合同与账单的统一客户主数据
- **怎么运作**:法务每 3 个月评估法律风险;财务实时维护财务风险等级;安全实时维护安全风险等级;系统综合形成签约策略
- **闭环**:未达禁止标准可签;偏离常规范式走「非标准流程」;达禁止标准禁止新签,现有合同标「高风险」并通知业务跟进或终止
#### 标准合同管理
- **起点**:法务部维护各车型试用/正式等标准模板,明确条款边界与风控要求
- **怎么运作**:数智部按模板配置电子合同;条款可设「触发车型」;「风控红线」被改进非标审批;「锁定区域」不可随意改
- **闭环**:业务员直选模板走标准流程;触碰红线或锁定区外修改转法务非标审批
#### 租赁合同
- **起点**:业务员选羚牛签约主体与乙方客户;系统按评级判标准/非标/禁止
- **怎么运作**:合同要素实时反写电子合同预览;生成电子合同/条款附件/授权委托书;越界转非标;支持续签、转正式、转三方、增值服务、授权委托书、主动终止等
- **闭环**:审批通过进入履约并串联提车应收、交车、台账;非标须法务与董事长确认后放行
#### 提车应收款
- **起点**:提交租赁合同审批时,按合同条款自动生成提车应收金额
- **怎么运作**:法务在「收款记录」导入到账(后期对接 YS/银企直联);业务/业管关联账单并分配金额;实收对齐后标记完成
- **闭环**:应收完成后按约定生成交车任务,属地运维执行交车
#### 租赁业务台账
- **起点**:运维交车成功后自动生成该车租赁账单,应付款日初始「待设置」
- **怎么运作**:设置应付款日后生成首期应收;提车实收写入首期;溢出并入第二期减免
- **闭环**:持续记录每期应收/实收/状态,支撑租期运营与还车结算
#### 还车应结款
- **起点**:运维完成还车后自动生成还车应结款任务
- **怎么运作**:业管、安全、运维、能源各自完成部门审批;汇总应退/应补;应补关联收款记录、应退关联付款记录
- **闭环**:业管发起总审批;完成后自动归档,租赁单条业务全链路闭环
---
### 4.2 能源
#### 供应商管理
- **起点**:加氢站/充电站作为供应商纳入统一体系,采购组维护基础信息与结算要素
- **怎么运作**:创建站点时绑定供应商;氢费/电费对账支持直连付款;收付款明细关联财务记录;支撑付款/收款申请审批
- **闭环**:供应商主数据与站点、对账、财务贯通,打好能源业财基础
#### 加氢站管理
- **起点**:采购部统一管理签约站/非签约站;签约站须关联供应商与系统账号
- **怎么运作**签约站账号登录加氢订单PC/移动/H5预付款余额营业状态成本价关联氢费记录能源部形成对账单并发起付款后期对接 YS
- **闭环**:站点/账号/余额/价格/营业状态集中管理,签约站可自助上报
#### 加氢订单
- **起点**签约站登录后多渠道上报订单PLC 站点可自动获取
- **怎么运作**多端快速识别记录PLC 自动获取;联动「小羚羚」预约接单,司机确认;进入加氢记录供对账
- **闭环**:主动上报或自动采集,预约在线闭环,减少手工补录
#### 车辆氢费明细
- **起点**:非签约站氢费由业务管理组-能源部手动维护
- **怎么运作**:录入并关联站点/车辆/客户对账后标「已对账」归档联动预付款余额与客户能源账户OCR 与电子围栏辅助核对
- **闭环**:签约/非签约氢费统一归集,余额变动可追溯
#### 氢费账户
- **起点**:管理客户氢费预付款余额与客户对账单
- **怎么运作**:维护余额变动;生成对账单;关联「收款记录」;收款后加氢记录标「已付款」;支持充值/开票直达财务(替代钉钉,对接 YS
- **闭环**:明细→对账→收款全链路可核对,付款状态与财务实收一致
#### 扩展规划
- **起点**:条线成熟后向上游采购与下游司机服务延伸
- **怎么运作**:上游氢气采购;下游外部氢能车司机服务;与现有供应商/站点/订单/账户衔接
- **闭环**:覆盖「采购—站点—用氢—结算—司机服务」更大范围生态
---
### 4.3 运维
#### 供应商管理
- **起点**:整车厂、三方租赁企业纳入供应商体系
- **怎么运作**:维护档案;为采购/三方租赁合同提供主数据;支撑付款底座
- **闭环**:与采购合同、付款记录贯通
#### 车辆采购 / 三方租赁合同
- **起点**:向整车厂/三方租赁厂商发起采购或三方租赁合同
- **怎么运作**:创建审批;关联付款记录;按条款自动生成验车任务
- **闭环**:合同、付款、验车联动,入库合规入口
#### 验车入库
- **起点**:对采购或三方来源氢能车执行验车
- **怎么运作**:接收验车任务;记录过程与问题;验完自动入库
- **闭环**:验车结果与合同、库存绑定,来源可审计
#### 车辆上牌
- **起点**:对仅有车架号的新车执行上牌
- **怎么运作**:筛选待上牌车;录入/同步牌照;更新库存状态
- **闭环**:牌证完整,为证照与交车提供前置条件
#### 证照管理
- **起点**:行驶证、道路运输证、登记证、特种设备证/标识、加氢卡、安全阀、压力表等一车一档
- **怎么运作**:维护档案与有效期;临近到期生成年审/等评/换证待办;推送运维/安全
- **闭环**:证照全生命周期管理,降低漏办与违规风险
#### 备车管理
- **起点**:日常提前整备,确保交车任务可随时交付
- **怎么运作**:按计划/库存策略发起检查;记录整备项与责任人
- **闭环**:交车前置完成,提升交付效率与质量一致性
#### 交车管理
- **起点**:承接租赁/物流交车任务,按区域派属地运维;司机先完成在线培训并留痕
- **怎么运作**:司机上传身份证/驾驶证/从业资格证、签名与现场拍照;交付证照及保险有效车辆;记录里程/氢量/电量/位置OCR 胎纹还车时比对算磨损等费用E 签宝电子签归档
- **闭环**:培训与交车数据完整可查,为还车费用与争议提供依据
#### 替换车管理
- **起点**:因客户或车辆原因发起临时/永久替换
- **怎么运作**:选类型与新旧车;完成替换交还;客户原因自动算费用差
- **闭环**:过程可追踪、费用可核算,履约不中断
#### 还车管理
- **起点**:处理业务/业管还车任务,按区域派属地运维
- **怎么运作**:记录还车时间/里程/氢电量/位置OCR 胎纹对比算磨损费按里程与氢电差算费用E 签宝确认归档
- **闭环**:费用依据交还对比自动出具
#### 故障管理
- **起点**:微信 AI 故障助手或人工记录故障关键信息
- **怎么运作**:记时间地点车型紧急程度;留存图文视频聊天证据;运维处理至关闭;形成待办统计;沉淀品牌故障类型统计支撑采购论证
- **闭环**:全过程留痕,证据链完整
#### 年审记录
- **起点**:按行驶证审验有效期提前 3 个月生成年审任务
- **怎么运作**:按车按月归集;完成后 OCR 新行驶证刷新证照;按月量化完成率
- **闭环**:任务不遗漏,证照与办理结果同步
#### 维修与保养记录
- **起点**:运维手动维护负责车辆维保记录(首期)
- **怎么运作**:配件费/人工费汇总;按承担方(客户/我司)生成客户账单或计入运维成本;计入车辆盈亏
- **闭环**:维保成本可追溯可分摊,支撑单车盈亏与对客户计费
#### 车辆异动
- **起点**:因当地维修/年审/保养出库异动,须提前审批
- **怎么运作**:记异动前后氢电量里程;异动期间加氢记录归集为异动成本
- **闭环**:可审批可计量,避免成本漏记
#### 车辆调拨
- **起点**:车辆从 A 地调至 B 地运营,须提前审批
- **怎么运作**:记发起方/费用/运输;接收方确认;运维操作权由 A 转 B
- **闭环**:跨区调拨透明,责任属地随车切换
#### 车辆出售、过户、报废
- **起点**:达出售/过户/报废条件发起资产变更,录入交易方价格过户残值等
- **怎么运作**:提交申请;董事长确认;运维记录全过程归档;完成后退出运营并出库
- **闭环**:处置审批留痕,生命周期闭环至出库归档
---
### 4.4 安全
#### 司机管理
- **起点**:管理物流内部司机,支撑快速选取与档案维护
- **怎么运作**:维护基础信息与在职状态;管理驾驶证/从业资格证;与交车、台账联动
- **闭环**:主数据统一、证照可查,支撑调度与合规
#### 内部司机培训
- **起点**:定期开展安全培训并形成可追溯记录
- **怎么运作**:制定计划组织参训;记录时间内容参训人;形成证据链供交管查询
- **闭环**:培训电子归档,随时可调阅
#### 安全培训资料库
- **起点**:安全部上传培训与安全运营资料供司机学习
- **怎么运作**:维护课件制度指引;分类发布版本检索;司机经 APP/小程序学习
- **闭环**:资料集中更新,移动端可学可查
#### 违规记录
- **起点**:记录内部司机运营违规
- **怎么运作**:登记事件类型时间结果;关联司机档案;联动客户安全评级
- **闭环**:违规可追踪汇总,支撑选用与评级
#### 违章管理
- **起点**:记录交通违章并与还车应结款联动
- **怎么运作**:登记时间地点分值罚款及是否缴纳;未处理纳入还车结算;逾期未缴自动生成代处理费用
- **闭环**:违章可查,代处理费用与还车/财务口径一致
#### 事故管理
- **起点**:记录事故信息,支撑定责理赔与还车结算
- **怎么运作**:登记权责划分;记保险介入/赔付/上浮;联动还车应结款写入安全费用
- **闭环**:登记→赔付→上浮→应结款贯通,费用不遗漏
---
### 4.5 物流
#### 物流合同
- **起点**:创建物流运力服务合同,录客户/车型/车辆数/交车时间地点,上传附件
- **怎么运作**:录入项目与合同要素;业务确认生效后可创建轻量调度并提示运维交车
- **闭环**:合同成为调度派车与交车的上游凭证
#### 调度任务
- **起点**:在生效合同下创建出车任务,派车派司机;非 TMS
- **怎么运作**:选合同、计划出车日、线路、是否多趟与计价口径;未交车须先交车;办结确认实际出车后自动生成物流业务明细一行
- **闭环**:出车事实追溯到合同与车牌,驱动台账落账
#### 物流台账
- **起点**:承接调度办结自动生成的出车明细,导入/行编辑补录异常与历史
- **怎么运作**:办结写入营收侧并算金额/总成本/盈亏;氢费/ETC 等成本可手工补录;汇集项目盈亏表;演进关联「收款记录」
- **闭环**:收入与司机/车辆成本同台账可核对,盈亏可对接财务实收
---
## 5. AutoRDO 应用约定
1. **标题**:优先 `模块标准名:核心动作/结果`1030 字),模块名以本词典为准(例:`验车入库:采购与三方租赁合同自动生成验车记录及入库`
2. **条线归属**:一句需求只挂一个主模块;跨条线联动写在描述里,不硬塞进标题
3. **部门用词**:口语「业管/能源组/运维」等映射到第 1 节标准名
4. **闭环口径**:若材料只讲做到一半,闭环写实际说到的结果,缺的标「待确认」
5. **不做**:不把本词典全文贴进云效描述或输出稿;不脑补材料未出现的故事点细节
6. **业财关键词**:收款记录、付款记录、对账单、应收/实收、YS、银企直联、E 签宝、小羚羚、PLC——保留原文业务对象名勿随意改写
---
## 6. 条线演进(辅助理解,非强制写入描述)
| 条线 | 现阶段 | 演进方向 |
|---|---|---|
| 租赁 | 合同电子化 · 业务闭环化 | 移动端商城直连发起合同,后续自动打通 |
| 能源 | 手工维护氢费明细 | 签约站主动上报,能源部转为核对确认 |
| 运维 | 车辆使用环节闭环 | 入库→运作→出库全链路 |
| 安全 | 司机安全全链条 | 与客户安全评级挂钩、事前预判 |
| 物流 | 合同 + 调度办结落账 | 成本自动回填、司机在线、关联收款;不做完整 TMS |
| 系统 | 业务驱动 · 财务手工 | 打通 YS · 业财一体 |

View File

@@ -0,0 +1,67 @@
# AutoRDO 清洗与拆解细则
## 目标
碎片 → 可入库的书面「标题」与「描述」。保留原意;不写成产品 PRD。
多行/多条独立输入 → **多份**转译结果(一份需求一份稿)。
## 必做与精炼规则
| 规则 | 说明 |
|---|---|
| **多条拆解** | 输入为多条独立诉求时,**先拆后洗**<br>• **拆分信号**(满足任一即可):换行且每行一句独立诉求;`1. 2. 3.` / `-` / `*` 列表;表格多行;空行分段;「另外」「还有」「第二条」等显式分条<br>• **每条**各自输出一份标题+描述+待确认,**禁止**合并成一条大需求<br>• **不拆**:同一条需求内部的续写、补充说明、功能规则子点(属于描述细节,挂在该条下)<br>• **边界不清**:无法判断是一条还是多条时,在文首标「待确认:拆条边界」,并按最可能的分条给出结果,请用户校对 |
| **OneOS 领域对齐** | 涉及 ONE-OS / 羚牛业务时,**先读** [oneos-domain.md](oneos-domain.md)<br>• 部门口语映射到标准名(业管→业务管理组,能源组→业务管理组-能源部 等)<br>• 标题模块名优先用词典标准名(如「验车入库」而非口语「验车管理」——若材料确指该模块)<br>• 跨条线联动写在描述,标题只挂主责模块<br>• **禁止**把词典全文或未在材料中出现的故事点细节写入输出 |
| **标题提炼** | 根据材料内容理解,自动概括简炼、清晰的标准需求标题:<br>• **内容理解**:准确识别归属的业务模块与核心动作/诉求(如:`验车入库:采购与三方租赁合同自动生成验车记录及入库`)。<br>• **自然流畅**:表达自然书面化,无需死板强求拼接固定句式;彻底剔除“我们要做一个”、“主要是用于”、“完成之后才能”等口语废话。<br>• **字数适中**:控制在 10-30 字内,能让读者一眼看懂需求核心。 |
| **元数据识别** | 详见 [meta-fields.md](meta-fields.md)。从台账列或正文自动识别并输出:<br>• **类型**`【新增】`/`【优化】`<br>• **优先级**`P1-高`/`P2-中`/`P3-低`<br>• **标签**:标准模块名(+ 可选 PC端/小程序)<br>• **提交部门**:映射词典标准名(业务管理部→业务管理组,数智中心→数智部 等)<br>• **提交人**:反馈方/用户列或署名<br>• 显式列优先;推断不确定则待确认;**不**直接写云效打标 |
| **描述转译** | 原文的转译结果,将口述/碎片材料转译为规范书面表达保留原意不改变谁要求什么、约束与例外不替换成「更优方案」业财对象名收款记录、付款记录、YS、E 签宝、小羚羚、PLC 等)按词典保留 |
| 书面化 | 口语改成完整句子或清晰短条目;主谓齐全 |
| 去口头禅 | 删除:嗯、啊、那个、就是说、然后呢、对对对、你懂吧 等 |
| 自我修正 | 以最后一次明确口径为准;若前后矛盾且未决,列入「待确认」 |
| 去重复 | 同一意思多轮确认只保留一处;多条拆解时,各条之间不要互相抄写无关内容 |
| 轻度格式 | 可用短标题/条目;禁止展开成总览/角色/流程图/故事点等 PRD 结构 |
| 去结尾句号 | 描述中每个句子或条目末尾去掉 `。`;保留 `` `` 若确为疑问/感叹 |
| 待确认 | 材料含糊处写 `待确认:…`,不臆造;**只要存在待确认,同轮强制**进入 [confirm-pending.md](confirm-pending.md) 的 Plan 逐条确认(无需用户再说「确认待确认」) |
| **待确认 Plan 确认** | 详见 [confirm-pending.md](confirm-pending.md)<br>• 清洗结果含待确认 → **立刻** `SwitchMode` → plan<br>• 按需求条号**逐点**确认;**优先选择题**25 项 +「其他/我补充」),选项用 `oneos-domain.md` 辅助<br>• 也支持用户粘贴**需求描述/补充说明**一次消解多点<br>• 确认后回填描述并移除已消解项;未确认不得写入定稿 |
## 多条拆解示例
**输入(多行):**
```text
还车应结款生成后自动展示违章事故信息,不必等安全员提交
验车完成后才能车辆入库
氢费账户对账单要能关联收款记录
```
**输出**3 份独立的「原始诉求AutoRDO每份各自标题+描述;不要揉成一条。
## 标题提炼对比示例
-**坏标题(直抄口语/带废话)**`我们现在要做一个验车管理功能主要是采购合同和三方租赁合同自动形成验车记录验车完成之后才能车辆入库`
-**好标题(自然清晰,覆盖标准模块)**`验车入库:采购与三方租赁合同自动生成验车记录及入库`(模块名对齐 oneos-domain
## 不做
- 不生成 AutoPRD 十章或「产品说明」
- 不写验收清单、故事点、mermaid
- 不改云效、不建【交付】/分析/设计
- 不加载 `yunxiao-requirement-lifecycle`
- 不把多条独立诉求合并成一条「大杂烩」需求
## 录音
1. 已有转写 → 按上文清洗转写稿并拆解标题与描述;转写中若含多条独立诉求,同样先拆后洗
2. 仅音频 → 回报「请提供转写文本后再 AutoRDO」停止声称已清洗完成
## 质量自检
- [ ] 多行/多条输入时,已按条拆成多份结果(条数与输入独立诉求数一致或已说明待确认边界)
- [ ] 已对照 `oneos-domain.md`ONE-OS 相关材料)
- [ ] **标题清晰通顺**(标准模块名 + 核心动作,无死板句式绑定,无口语废话)
- [ ] 部门/业财关键词已映射或保留为词典标准口径
- [ ] **描述为原文的转译结果**,干系人能认出这是自己说的意思;未脑补词典故事点
- [ ] 无口头禅堆砌、无未决矛盾被写成定论
- [ ] 描述末尾无 `。`
- [ ] 未冒充完整 PRD未把词典全文写入输出
- [ ] 已输出类型/优先级/标签/提交部门/提交人(有依据或已标待确认;未臆造提交人)
- [ ] 若存在待确认:已同轮强制进 Plan未等「确认待确认」口令优先选择题、选项有词典依据文字补充已映射到对应点定稿无未确认臆造
- [ ] 若无待确认:未多余进 Plan

View File

@@ -0,0 +1,113 @@
---
name: YunxiaoPM
description: >-
产品经理云效Projex自动化记录需求压缩点选 1a2b3a4d类型/项目/优先级/标签)、
实时点选云效项目、推进 待处理→已确认→分析中→设计中→设计完成→待开发,
交付树【交付】ASSOCIATED /【分析】【设计】TASK_SUB无单快轨与编号直推交棒何斐
创建迭代并挂【交付】(不挂需求)。用户说 YunxiaoPM、YunxiaoPMapp、需求任务、记录需求、受理确认、开始分析、
开始设计、设计完成、交棒开发、快轨待开发、编号直推、创建迭代 时使用。
不建【开发】/【测试】。凡写云效先 Plan 确认再一口气 apply禁止对齐
yunxiao-requirement-lifecycle。
---
# 需求任务YunxiaoPM
产品部云效自动化。斜杠调起 **`/YunxiaoPM`**;对外中文名 **需求任务**(原名 YunxiaoPMapp。本 Skill **自洽成篇****禁止** fork / include / 「对齐」`yunxiao-requirement-lifecycle`
产品经理会话**不要**同时挂载旧 lifecycle Skill避免双建任务。
## Plan 模式门禁(强制 · 凡写云效)
凡会改云效的操作(建单、改状态、建/改任务、打标、传附件、改负责人、建迭代等Agent **第一步**必须:
1. `SwitchMode`**plan**(说明:先对齐参数与执行清单,确认后再一口气 apply
2. **新建**依赖项目空间时:先按 [references/project-selection.md](references/project-selection.md) **实时拉项目列表并点选(门禁 PJ**;禁止静默使用 `runtime-ids.json` 默认 `spaceIdentifier`。口令/选项**无法对应**时:**自动重拉项目列表一次**再匹配;仍失败则停请用户重选(禁止第 3 次空转拉取)。
3. Plan 写清:**已选项目名 + spaceId**、目标需求/任务**编号**、将改状态、将建/复用的交付·分析·设计编号策略、迭代版本类型若适用、§0.1① 占位风险勾选(若适用)、**不会做的事**(不建【开发】/【测试】、不按标题查重)。**记录需求**须按 [compact-select.md](references/compact-select.md) 给出 14 题字母表,接受压缩答复如 `1a2b3a4d`
4. **用户确认 / 批准 Plan / 「执行」之前**:禁止 apply项目未点选同禁。压缩串须先解析回显再等「执行」。
5. 确认后切回 Agent**同一轮按清单一口气执行到底**,再一次性校验回报;中途缺参才停下。
**例外(可读可不进 Plan** 仅查状态 / 为什么没流转 / 给我方案。
**禁止:** 以「参数已齐」「速度路径」「用户很熟」跳过 Plan「批准计划」若清单未点齐关键参数**PJ 项目**),仍视为未完成门禁。
## 真相源模型
```text
需求状态 = 阶段看板唯一真相
【交付】 = 每需求最多 1 条容器ASSOCIATED→需求
【分析】/【设计】 = TASK_SUB→交付交付「子项」必可见与 ASSOCIATED 同 create 互斥)
【开发】/【测试】 = 不进本 Skill
查重/复用唯一渠道 = 任务编号ONEOS-xx禁止按标题
```
编号权威:需求描述 `## 工作项编号(系统)`(见 [references/workitem-ids.md](references/workitem-ids.md))。
操作顺序:口令显式编号 > 读该区块 > ASSOCIATED/SUB 校验;冲突则停。
## 外置调用(禁止本 Skill 内嵌对方全文)
| 时机 | 调用 |
|---|---|
| 入库清洗聊天/录音 | **`$AutoRDO`**(独立 Skill路径 `AutoRDO/SKILL.md`;不内嵌清洗细则) |
| 设计完成 PRD + 对象存储链接 + 回填【交付】 | **`$oneos-autoprd`AutoPRD**;创建【交付】仍占位,设计完成才灌 MD |
| 人员 / 状态 / 字段 ID项目 catalog 仅缓存 | [assets/runtime-ids.json](assets/runtime-ids.json) |
| **PJ 云效项目点选**(新建必选;实时列表) | [references/project-selection.md](references/project-selection.md) · [scripts/list_projects.py](scripts/list_projects.py) |
| **压缩点选 `1a2b3a4d`**(类型/项目/优先级/标签) | [references/compact-select.md](references/compact-select.md) · [scripts/list_tags.py](scripts/list_tags.py) |
| 阶段日历工时 | [references/work-hours.md](references/work-hours.md) + [assets/cn-workday-calendar.json](assets/cn-workday-calendar.json) + [scripts/workday_hours.py](scripts/workday_hours.py) |
## 路由(按需完整阅读)
| 场景 | 模块 |
|---|---|
| 交付树、关联约定、禁止项 | [references/model.md](references/model.md) |
| 描述双段 · AutoRDO / 占位 / AutoPRD | [references/description-split.md](references/description-split.md) |
| 步骤 05 标准路径 | [references/stage-flow.md](references/stage-flow.md) |
| 无单快轨到待开发 | [references/fast-track.md](references/fast-track.md) |
| 编号直推交棒 | [references/number-push.md](references/number-push.md) |
| 交棒门禁 · 回退最小集 | [references/handoff-and-rollback.md](references/handoff-and-rollback.md) |
| 计划开始/完成 · 阶段日历工时 | [references/work-hours.md](references/work-hours.md) |
| Make 导出 ZIP + 复制截图 | [references/make-export-attach.md](references/make-export-attach.md) |
| 创建迭代 · V主.副.子 · 只挂交付 | [references/sprint.md](references/sprint.md) |
| 口令面 | [references/commands.md](references/commands.md) |
| 记录需求元字段(优先级/标签/提交部门/提交人) | [references/record-meta-fields.md](references/record-meta-fields.md) |
| 云效项目点选 PJ | [references/project-selection.md](references/project-selection.md) |
| 验收清单 · 回报模板 | [references/acceptance.md](references/acceptance.md) |
| 交接契约(开发 Skill 入口) | [references/handoff-contract.md](references/handoff-contract.md) |
| 已验证实写 API · 极速建单 | [references/live-api.md](references/live-api.md) · [scripts/live_create_fast.py](scripts/live_create_fast.py) |
| 2026-07-23 复盘与耗时对比 | [references/live-perf-2026-07-23.md](references/live-perf-2026-07-23.md) |
## 口令速查
```text
记录需求:…;项目=Plan 点选,勿默认);优先级=紧急|高|中|低;标签=…;提交部门=…;提交人=…;推进至=暂不推进|已确认|分析中|设计中|设计完成|待开发|待开发(快轨)
受理确认ONEOS-xx
开始分析ONEOS-xx
开始设计ONEOS-xx交付任务=…;分析任务=…
设计完成ONEOS-xx设计任务=…;原型=…
交棒开发ONEOS-xx交付任务=…
快轨待开发ONEOS-xx
编号直推:分析任务=ONEOS-b / 设计任务=ONEOS-c / 交付任务=ONEOS-a
创建迭代:版本类型=主|副|子;交付任务=ONEOS-a,ONEOS-b,…;名称前缀=…
```
**PJ 项目**:新建前必须从云效实时列表点选(见 [project-selection.md](references/project-selection.md));口令带项目名仅作预填建议。
**压缩点选**:记录需求 Plan 展示 `1.类型 2.项目 3.优先级 4.标签` 字母表;你可回 `1a2b3a4d`(见 [compact-select.md](references/compact-select.md))。标签未命中会自动重拉一次标签候选并重生选项。
**记录需求**元字段(优先级/标签/提交部门/提交人):与压缩点选并用;缺项用字母表补齐。见 [references/record-meta-fields.md](references/record-meta-fields.md)。
后续口令**优先带任务编号**;未带则读「工作项编号(系统)」;仍无则询问;**禁止按标题补全**。
## 本 Skill 终点
交棒完成(需求=待开发;【交付】负责人=何斐)后结束。可一句:「请技术经理使用开发 Skill」。
例外:交棒后「创建迭代并关联交付」仍属 YunxiaoPM。
**明确不做:** 创建【开发】/【测试】、挂仓库、开分支、提测、写用例。
## §0.1 五条补齐(摘要)
1. **交棒占位**:标准路径下交付仍为 `等待设计任务完成后自动填入` 时**允许**交棒,但 Plan 必须勾选风险,回报首行标红。**快轨**有手工/原型时禁止占位(见 [fast-track.md](references/fast-track.md))。
2. **预计工时**:标准路径 = **阶段日历工时**工作日×8**快轨待开发**需求默认预计/实际各 **2**
3. **编号真相源**在需求「工作项编号(系统)」;新建后立即 PATCH 该区块。
4. **无单快轨**:【设计】描述同步需求;计划起止=当日TASK_SUB→交付后补 ASSOCIATED→需求【交付】描述手工同步或 AutoPRD交付/设计与需求同标签;设计当日完成态。
5. **描述双段**不互相覆盖;迭代**只挂【交付】**(需求不挂迭代);回退重做设计则**新开设计编号**,交付计划开始不改。
细则见各 references。

View File

@@ -0,0 +1,49 @@
# 验收清单与回报
## apply 后必须自检
| # | 项 | 通过标准 |
|---|---|---|
| 1 | 需求编号 | 回报含 ONEOS-xx |
| 2 | 任务编号 | 交付/分析/设计凡新建或操作均回报编号;禁止只报标题 |
| 3 | 编号区块 | 需求「工作项编号(系统)」与实际一致 |
| 4 | ASSOCIATED | **仅交付**详情关联项可见需求(`createWorkitemRelationInfo=ASSOCIATED`;禁止 PARENT 冒充) |
| 5 | SUB | **必过**:分析/设计 create 用 `TASK_SUB→交付`(含 `parent`+`parentIdentifier`交付「子项」tab 须可见。与 ASSOCIATED 同 create 互斥,阶段任务关联项可空(见 live-api.md |
| 6 | 计划开始 | 未误覆盖已有值 |
| 7 | 阶段日历工时 | 有计划完成时已写入;脚注存在;回报用语正确 |
| 8 | 交棒 | 需求=待开发;交付负责人=何斐(交棒场景) |
| 9 | 占位风险 | 交付仍占位时首行标红 |
| 10 | 负向 | 本轮**无**【开发】/【测试】任务;未按标题查重 |
设计完成额外AutoPRD 段已写交付非占位除非失败停下ZIP+截图已挂或已列出缺项。
迭代额外:只挂【交付】(需求不挂);版本号符合递增规则。
## 回报模板(精简)
```text
【YunxiaoPMapp】
风险:(若有占位交棒则首行标红)
需求ONEOS-xx | 状态=…
交付ONEOS-a | 负责人=…
分析ONEOS-b | …(无则写无)
设计ONEOS-c | …(无则写无)
阶段日历工时:分析 Hh / 设计 Hh若本轮写入
附件:…(若本轮)
迭代:…(若本轮)
下一步:请技术经理使用开发 Skill交棒后
```
## 适合全自动 vs 人工门禁
| 适合全自动 | 建议半自动/人工门禁 |
|---|---|
| 建单、打标签、挂迭代、写描述、建交付树、改状态、交棒负责人、幂等查重 | 受理(已确认)、是否快轨、设计完成是否真可开发、跨需求优先级与迭代容量、回退与取消 |
## 实写性能2026-07-23 复盘)
| 项 | 要求 |
|---|---|
| 改状态 | 只用 `status/transit`(见 [live-api.md](live-api.md) |
| 改【交付】负责人 | 只用 `PATCH …/{id}` + `propertyKey=assignedTo` |
| 极速复测 | `scripts/live_create_fast.py`;默认不开浏览器 |

View File

@@ -0,0 +1,4 @@
interface:
display_name: "需求任务"
short_description: "云效:压缩点选记录需求→分析/设计→交棒待开发→挂迭代"
default_prompt: "按需求任务(/YunxiaoPM处理先 Plan 出压缩点选字母表并确认项目,用户回 1a2b3a4d 与「执行」后再 apply。"

View File

@@ -0,0 +1,95 @@
{
"schema_version": 1,
"timezone": "Asia/Shanghai",
"note": "法定放假日 holidays国务院公布的周末调休补班日 workdays_on_weekend。缺年则禁止静默按仅去周末计算。",
"source": {
"2025": "国办发明电202412号 https://www.gov.cn/zhengce/zhengceku/202411/content_6986383.htm",
"2026": "国办发明电20257号 https://www.gov.cn/zhengce/content/202511/content_7047090.htm"
},
"years": {
"2025": {
"holidays": [
"2025-01-01",
"2025-01-28",
"2025-01-29",
"2025-01-30",
"2025-01-31",
"2025-02-01",
"2025-02-02",
"2025-02-03",
"2025-02-04",
"2025-04-04",
"2025-04-05",
"2025-04-06",
"2025-05-01",
"2025-05-02",
"2025-05-03",
"2025-05-04",
"2025-05-05",
"2025-05-31",
"2025-06-01",
"2025-06-02",
"2025-10-01",
"2025-10-02",
"2025-10-03",
"2025-10-04",
"2025-10-05",
"2025-10-06",
"2025-10-07",
"2025-10-08"
],
"workdays_on_weekend": [
"2025-01-26",
"2025-02-08",
"2025-04-27",
"2025-09-28",
"2025-10-11"
]
},
"2026": {
"holidays": [
"2026-01-01",
"2026-01-02",
"2026-01-03",
"2026-02-15",
"2026-02-16",
"2026-02-17",
"2026-02-18",
"2026-02-19",
"2026-02-20",
"2026-02-21",
"2026-02-22",
"2026-02-23",
"2026-04-04",
"2026-04-05",
"2026-04-06",
"2026-05-01",
"2026-05-02",
"2026-05-03",
"2026-05-04",
"2026-05-05",
"2026-06-19",
"2026-06-20",
"2026-06-21",
"2026-09-25",
"2026-09-26",
"2026-09-27",
"2026-10-01",
"2026-10-02",
"2026-10-03",
"2026-10-04",
"2026-10-05",
"2026-10-06",
"2026-10-07"
],
"workdays_on_weekend": [
"2026-01-04",
"2026-02-14",
"2026-02-28",
"2026-05-09",
"2026-09-20",
"2026-10-10"
]
}
}
}

View File

@@ -0,0 +1,221 @@
{
"schema_version": 1,
"skill": "YunxiaoPM",
"verified_at": "2026-07-25",
"note": "YunxiaoPM constants. Project space MUST be user-selected (PJ gate); project.spaceIdentifier is last-known cache only — never auto-apply. See references/project-selection.md.",
"project": {
"selection_mode": "user_pick_required",
"name": null,
"name_aliases": [
"01_ONEOS",
"ONEOS",
"统一运营管理平台",
"统一运营管理平台PC端",
"统一运营管理平台 PC 端"
],
"spaceIdentifier": null,
"customCode": null,
"spaceType": "Project",
"organizationIdentifier": "697c54a19df7fdfa65466405",
"default_sprint_name_prefix": "统一运营管理平台PC端",
"list_api": "GET /projex/api/workspace/project/search/list",
"last_selected": {
"name": "01_ONEOS",
"spaceIdentifier": "1280be963a5a2cc126a4118dca",
"customCode": "ONEOS",
"note": "历史常用项;仅作预填建议,禁止未点选即使用"
},
"refreshed_at": "2026-07-25"
},
"projects_catalog": [
{
"name": "05_羚牛碳资产平台",
"identifier": "ff104a3bce09463da136a97999",
"customCode": "CARBON"
},
{
"name": "06_对外客户项目",
"identifier": "baca8b4d676c5af67e475caec0",
"customCode": "CUST"
},
{
"name": "07_LNBOX",
"identifier": "35e1e915a052379bbdfb993aac",
"customCode": "LNBOX"
},
{
"name": "04_AI应用",
"identifier": "d9002ea72c6c3a1a97b02be750",
"customCode": "AIAPP"
},
{
"name": "03_数据中台",
"identifier": "a801cef5c9a68fa051c07432c7",
"customCode": "DATA"
},
{
"name": "02_小羚羚APP",
"identifier": "db771a2cca07bed43b369af077",
"customCode": "XLLAPP"
},
{
"name": "01_ONEOS",
"identifier": "1280be963a5a2cc126a4118dca",
"customCode": "ONEOS"
},
{
"name": "敏捷研发示例项目",
"identifier": "65eca0c2e16a23939081e19e14",
"customCode": "DEMO"
}
],
"people": {
"wangmian": {
"displayName": "王冕",
"identifier": "6811df000601d2fea60144a9",
"role": "产品创建人/默认负责人"
},
"hefei": {
"displayName": "何斐",
"identifier": "695f0400562f09713f9c3a93",
"role": "待开发交棒【交付】负责人"
}
},
"tags": {
"故障管理": "ceb526a7343995577645317e9a",
"还车应结款": "4204960ce658c94b17abb7c5f6",
"工作台": "b62d21beac55c0b43389915eab",
"交车管理": "b6947b5aca82a8c759612ba039",
"合同管理": "23873be81931cb0dc1bf87a456",
"安全培训": "76988b5f73ef515de5930d59b9",
"证照管理": "11f4c2ec65901a8f3199c81706",
"还车管理": "1e0fce2d6929ff4ac13b310e97"
},
"status": {
"req": {
"待处理": "100005",
"已确认": "32",
"分析中": "154395",
"设计中": "156603",
"设计完成": "307012",
"待开发": "1582fc929d429111b925309493"
},
"task": {
"待处理": "100005",
"已完成": "100014"
},
"transit_api": "POST /projex/api/workitem/workitem/{id}/status/transit",
"fast_handoff_hops": [
"设计完成",
"待开发"
],
"note": "见 references/live-api.md禁止再用 updateStatus"
},
"workitem_types": {
"product_req": {
"name": "产品类需求",
"category": "Req",
"identifier": "9uy29901re573f561d69jn40"
},
"task": {
"name": "任务",
"category": "Task",
"identifier": "ba102e46bc6a8483d9b7f25c"
}
},
"priority": {
"紧急": "646004e97f54bb77fec7b455df",
"高": "95b89e0a524d9693e1f335ffe5",
"中": "fa155d1214f9f8db222d39db3b",
"低": "92924feff9c1085891e7511872"
},
"fields": {
"plan_start": {
"fieldIdentifier": "79",
"name": "计划开始时间",
"value_shape": "YYYY-MM-DD HH:mm:ss China wall time preferred; epoch ms string also accepted",
"example": "2026-07-27 12:00:00",
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
},
"plan_end": {
"fieldIdentifier": "80",
"name": "计划完成时间",
"value_shape": "YYYY-MM-DD HH:mm:ss or epoch ms string",
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
},
"estimated_hours": {
"fieldIdentifier": "101586",
"name": "预计工时",
"note": "不可直接改字段;须工时预估登记",
"create_api": "POST /projex/api/workitem/workitem/time/estimate body spentTime,type,recordUserIdentifier,workitemIdentifier",
"delete_api": "DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}",
"list_api": "GET /projex/api/workitem/workitem/time/estimate/list?workitemIdentifier="
},
"actual_hours": {
"name": "实际工时",
"note": "快轨待开发默认 2",
"create_api": "POST /projex/api/workitem/workitem/time body actualTime,type,recordUserIdentifier,workitemIdentifier,gmtStart,gmtEnd (epoch ms string)",
"list_api": "GET /projex/api/workitem/workitem/time/list?workitemIdentifier=",
"fast_track_default": 2,
"verified_at": "2026-07-27",
"verified_on": "ONEOS-293"
},
"fast_track": {
"req_estimated_hours": 2,
"req_actual_hours": 2,
"design_plan_start_end_same_day": true,
"design_description": "copy_req_document",
"delivery_description": "manual_sync_or_autoprd",
"delivery_design_same_tags_as_req": true,
"design_associated_to_req_after_task_sub": true,
"document_update_api": "PATCH /projex/api/workitem/workitem/{id}/document {content,formatType:RICHTEXT}"
},
"submit_department": {
"fieldIdentifier": "3132597a9718d1c282b7ba5a0c",
"name": "提交部门",
"format": "string input",
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
"verified_at": "2026-07-27",
"verified_on": "ONEOS-293"
},
"submitter": {
"fieldIdentifier": "9e01269e96f91fbb97d36bf5b3",
"name": "提交人",
"format": "string input",
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
"verified_at": "2026-07-27",
"verified_on": "ONEOS-293"
},
"tag": {
"fieldIdentifier": "tag",
"name": "标签",
"propertyKey": "tag"
}
},
"assignee_rules": {
"待开发_交付任务": "hefei",
"分析中_交付与分析": "creator",
"设计中_设计": "creator"
},
"relation": {
"delivery_to_req": "ASSOCIATED",
"stage_to_delivery": "TASK_SUB",
"create_field": "createWorkitemRelationInfo",
"forbid": [
"PARENT_as_关联项",
"ASSOCIATED_only_for_stage_tasks_without_TASK_SUB"
],
"note": "交付必须 ASSOCIATED→需求。分析/设计默认 TASK_SUB→交付子项 tab。二者同 create 互斥。见 references/live-api.md"
},
"delivery_placeholder": "等待设计任务完成后自动填入",
"task_title_prefixes": {
"delivery": "【交付】",
"analysis": "【分析】",
"design": "【设计】"
},
"publish_url": {
"shape": "{baseUrl}/{prototype-id}/index.html",
"forbid_prototypes_prefix": true,
"require_index_html": true
}
}

View File

@@ -0,0 +1,317 @@
# YunxiaoPMapp 实现原理说明
> 供**开发部门**设计 / 制作「开发侧 Skill」暂称 **YunxiaoDevapp**)时对齐契约。
> 本文描述产品侧 Skill **YunxiaoPMapp** 的模型、边界、数据契约与交棒接口;**不是**对 `yunxiao-requirement-lifecycle` 的兼容说明。
> 技能包https://github.com/15810879921-coder/oneos-pm-skills · `skills/YunxiaoPMapp/`
> 文档版本2026-07-24
---
## 1. 为什么拆成两个 Skill
| | YunxiaoPMapp产品 | 开发 Skill待建 |
|---|---|---|
| 职责 | 需求从「待处理」到「待开发」交棒 | 从「待开发」到开发完成 / 提测前 |
| 任务类型 | 【交付】【分析】【设计】 | 【开发】(可多条)、可选挂仓库/分支 |
| 负责人交接 | 交棒时【交付】→ **何斐** | 拆【开发】子任务并指派研发 |
| 明确不做 | 建【开发】/【测试】、开分支、提测 | 不建【分析】/【设计】、不改 AutoRDO 段 |
**硬规则:** 两个 Skill **禁止互相 include / fork 全文**;只认本文第 6 章「交棒契约」。产品会话与开发会话不要同时挂载旧 `yunxiao-requirement-lifecycle`,避免双建任务树。
---
## 2. 核心真相源(必须先统一)
```text
需求状态 = 阶段看板唯一真相(分析中 / 设计中 / 待开发 …)
【交付】任务 = 每需求最多 1 条「交付容器」
【分析】【设计】 = 【交付】下的阶段子项(产品侧建)
【开发】【测试】 = 开发 / 测试 Skill 建(产品侧永不创建)
查重 / 复用 = 只认云效任务编号 ONEOS-xx禁止按标题
```
### 2.1 关系模型(云效)
```mermaid
flowchart TB
Req["产品类需求 ONEOS-R"]
DEL["【交付】ONEOS-a"]
AN["【分析】ONEOS-b"]
DE["【设计】ONEOS-c"]
DEV["【开发】… 开发 Skill"]
TEST["【测试】… 测试 Skill"]
DEL -->|"ASSOCIATED 关联项"| REQ
AN -->|"TASK_SUB 子项"| DEL
DE -->|"TASK_SUB 子项"| DEL
DEV -.->|"建议SUB→交付 或 ASSOCIATED→需求+交付"| DEL
TEST -.->|"测试 Skill"| REQ
```
| 关系 | 谁写 | 验收 |
|---|---|---|
| `ASSOCIATED` | **仅【交付】→ 需求** | 交付详情「关联项」可见需求 |
| `TASK_SUB` | 【分析】/【设计】→【交付】 | 交付详情「子项」可见阶段任务 |
| (开发侧建议) | 【开发】→【交付】或需求 | 由开发 Skill 自定,但须可编号查重 |
**踩坑(已复现):** 对分析/设计只写 `parentIdentifier` + `ASSOCIATED→需求`交付「子项」会为空。正确create 时 `createWorkitemRelationInfo=TASK_SUB` + `parent`/`parentIdentifier`=交付。同一 create **只能**带一条关系ASSOCIATED 与 TASK_SUB 互斥。
### 2.2 标题只是展示
- 形式:`【交付】`/`【分析】`/`【设计】` + 需求标题
- **不参与查重**;改标题不影响幂等
- 开发侧【开发】标题建议 `【开发】` + 范围简述,同样**只认编号**
---
## 3. 编号权威源
需求描述固定区块(机器可解析):
```markdown
## 工作项编号(系统)
- 交付ONEOS-a
- 分析ONEOS-b无则写无
- 设计ONEOS-c无则写无
```
| 规则 | 说明 |
|---|---|
| 新建后立即 PATCH | 只改本区块,不动 AutoRDO / AutoPRD |
| 操作顺序 | 口令显式编号 > 读本区块 > ASSOCIATED/SUB 反查 |
| 冲突 | 停下人工;**禁止按标题猜** |
| 多交付编号 | 停止并列号请人合并 |
**开发 Skill 入口建议:** 口令必须带 `需求=ONEOS-R` + `交付任务=ONEOS-a`;缺则读本区块;仍无则询问。
---
## 4. 需求描述双段(产品写 · 开发只读)
```markdown
## 原始诉求AutoRDO
(聊天/录音清洗稿;设计完成也不删)
## 产品说明AutoPRD
(设计完成才灌满;含对象存储预览链接)
## 工作项编号(系统)
- 交付 / 分析 / 设计
```
| 段 | 谁写 | 开发侧用法 |
|---|---|---|
| AutoRDO | `$AutoRDO` → 产品记需求时 | 占位交棒时**唯一可信**业务原文 |
| AutoPRD | `$oneos-autoprd` → 设计完成时 | 正式需求说明;缺则有权要求产品补设计完成 |
| 编号区块 | YunxiaoPMapp | 定位交付树 |
**【交付】描述:** 设计完成前固定占位文案 `等待设计任务完成后自动填入`;设计完成后替换为 AutoPRD 正文。
**允许占位交棒**,但产品回报必须标红风险;开发 Skill 应检测占位并提示「材料不齐,可凭 AutoRDO 开工或退回补设计」。
对象存储预览 URL 形态:`{baseUrl}/{prototype-id}/index.html`(禁止加 `prototypes/` 前缀、禁止去掉 `index.html`)。
---
## 5. 产品侧阶段状态机0→5
```text
0 创建需求(待处理) ─AutoRDO→ 仅需求,不建任务
1 受理确认(已确认) 仍不建任务
2 分析中 建【交付】+【分析】
3 设计中 建【设计】;收口【分析】计划完成
4 设计完成 收口【设计】AutoPRD+附件;灌【交付】描述
5 待开发交棒 ★ 需求→待开发;【交付】负责人→何斐
★ = YunxiaoPMapp 终点 / 开发 Skill 起点
```
### 5.1 各步要点(开发需知道的副作用)
| 步骤 | 需求状态 | 任务侧关键动作 |
|---|---|---|
| 2 分析中 | 分析中 | 新建【交付】ASSOCIATED→需求描述=占位;计划开始仅空写当日且**此后不可改**新建【分析】TASK_SUB→交付 |
| 3 设计中 | 设计中 | 新建【设计】;【分析】计划完成=当日 + 阶段日历工时 |
| 4 设计完成 | 设计完成 | 【设计】完成态;需求+交付挂 ZIP/截图;交付描述换正式说明 |
| 5 交棒 | **待开发** | **只改交付负责人→何斐**;不新建分析/设计;不写交付计划完成 |
### 5.2 两条旁路(仍交到同一终点)
| 路径 | 前提 | 行为 |
|---|---|---|
| **无单快轨** | 尚无分析路径 / 明确跳过分析 | 待开发 + 新建交付+设计(设计当日收口);**不建分析**;默认可不跑 AutoPRD |
| **编号直推** | 已有分析/设计**编号** | 收口空计划完成 → 待开发 + 交付交棒何斐;不新建冗余单 |
---
## 6. 交棒契约(开发 Skill 必须实现)
### 6.1 入口条件(产品已完成)
```text
需求状态 = 待开发
【交付】任务编号 = ONEOS-a唯一
【交付】负责人 = 何斐
【交付】ASSOCIATED → 该需求
可选:分析/设计编号在「工作项编号(系统)」中
```
### 6.2 开发 Skill 建议入口口令
```text
接手开发:需求=ONEOS-R交付任务=ONEOS-a
拆分开发:交付任务=ONEOS-a范围=前端|后端|…;负责人=…
开始开发:开发任务=ONEOS-d
开发完成:开发任务=ONEOS-d
```
### 6.3 开发 Skill 建议职责边界
| 应做 | 不应做 |
|---|---|
| 在【交付】下建一条或多条【开发】(编号幂等) | 再建【分析】/【设计】或第二套【交付】 |
| 正式关联:建议 SUB→交付或同时 ASSOCIATED→需求 | 只按标题「【开发】xxx」查重 |
| 挂仓库 / 分支 / MR按你们 Codeup 规范) | 覆盖需求 AutoRDO 段 |
| 改【开发】状态与负责人 | 擅自把需求从待开发退回(除非产品授权回退口令) |
| 检测交付描述是否仍为占位并提示 | 假装 AutoPRD 已齐全 |
| 全部【开发】完成后通知测试 Skill / 建【测试】 | 在产品 Skill 会话里混跑 |
### 6.4 共享常量(可引用,勿整包加载)
路径均在 `skills/YunxiaoPMapp/assets/`
| 文件 | 内容 |
|---|---|
| `runtime-ids.json` | 项目 spaceId、何斐 ID、工作项类型、状态 transit、字段 79/80 |
| `cn-workday-calendar.json` | 法定节假日 / 调休(阶段日历工时) |
开发侧可复制一份到自己的 `assets/`,或只读引用短路径;**不要**把 YunxiaoPMapp 的 references 全文 include 进开发 Skill。
---
## 7. 计划时间与「阶段日历工时」
产品侧口径(开发侧若写计划时间建议对齐语义):
| 对象 | 计划开始 | 计划完成 | 预计工时 |
|---|---|---|---|
| 【交付】 | 首次分析中空则写当日,**永不覆盖** | 产品侧不写(留给上线) | 一般不推全周期 |
| 【分析】【设计】 | 创建时空则写当日,**永不覆盖** | 阶段收口日 | `工作日×8` |
```text
预计工时 = 阶段日历工时Lead Time≠ 人力投入人天
算法起止日含首尾扣周末与法定假计入调休补班×8 小时
禁止:(结束−开始+1×8 的自然日算法
```
脚注固定:`【系统】预计工时=阶段日历工时工作日×8非人力投入预估`
脚本:`scripts/workday_hours.py`
**建议:** 开发 Skill 若给【开发】写预计工时,在文档中明确是「人力投入预估」还是「阶段日历工时」,避免与产品侧混称。
---
## 8. Agent 运行时原理(制作 Skill 时照抄模式)
### 8.1 Plan 门禁
凡写云效:`SwitchMode → plan` → 用户确认 → 一口气 apply → 一次校验回报。
禁止用「参数已齐 / 速度路径」跳过 Plan。
### 8.2 模块化路由
`SKILL.md` 只做路由与门禁;细则在 `references/*.md`;常量在 `assets/`;脚本在 `scripts/`
外置能力AutoRDO、AutoPRD**调用对方 Skill**,不内嵌对方全文。
### 8.3 幂等
```text
幂等键 = 项目 + 需求编号 + 任务类型角色(交付/分析/设计/开发…)+ 已登记任务编号
命中编号 → 复用并补缺字段;禁止新建第二条同角色主容器(交付唯一)
```
### 8.4 验收与回报
每次 apply 后自检(产品侧清单见 `references/acceptance.md`)。开发侧建议至少回报:
```text
【YunxiaoDevapp】
需求ONEOS-R | 状态=待开发|开发中|…
交付ONEOS-a | 负责人=…
开发ONEOS-d1, ONEOS-d2 | …
仓库/分支:…
下一步:…
```
### 8.5 已验证写路径(可复用思路)
| 动作 | 约定(见 live-api.md |
|---|---|
| 改状态 | `POST …/status/transit`(勿用错误 updateStatus |
| 改负责人 | `PATCH …/{id}` + `propertyKey=assignedTo` |
| 建单关系 | create 带 `createWorkitemRelationInfo` |
| 极速复测 | `scripts/live_create_fast.py`(可参考,开发侧另写自己的脚本) |
---
## 9. 回退最小集(开发需配合)
| 场景 | 产品侧规则 | 开发侧注意 |
|---|---|---|
| 待开发 → 退回设计中 | 需求回退;交付负责人可改回产品;**交付计划开始不改**;重做设计则**新开设计编号** | 已建【开发】是否取消 / 暂停由开发 Skill 定义;勿静默删编号 |
| 设计完成后需求大变 | Plan 问是否回退;更新 AutoPRDAutoRDO 保留+变更纪要 | 勿覆盖 AutoRDO |
| 取消需求 | 任务标取消;不删编号区块 | 同步取消未完成【开发】 |
---
## 10. 建议的「YunxiaoDevapp」目录骨架
```text
YunxiaoDevapp/
├── SKILL.md # 门禁 + 路由 + 边界(引用本文契约,不 include PMapp
├── assets/
│ └── runtime-ids.json # 可从 PMapp 复制/裁剪
├── references/
│ ├── model.md # 【开发】与交付/需求的关系约定
│ ├── handoff-intake.md # 认交付编号 + 占位检测
│ ├── split-dev-tasks.md # 拆前端/后端多【开发】
│ ├── codeup.md # 分支 / MR / 关联
│ ├── commands.md # 口令面
│ └── acceptance.md
└── scripts/ # 可选极速 API
```
`SKILL.md` description 建议写明:触发词「接手开发 / 拆分开发 / 开始开发」;**Does NOT create 【分析】/【设计】**;入口条件需求=待开发。
---
## 11. 对照检查表(开发 Skill 评审用)
- [ ] 是否只认「需求编号 + 交付任务编号」,禁止标题查重
- [ ] 是否拒绝创建第二套【交付】或【分析】【设计】
- [ ] 占位交棒时是否提示风险且不假装 PRD 齐全
- [ ] 【开发】是否可编号幂等、可挂到交付树
- [ ] 是否与 YunxiaoPMapp **会话隔离**(不同 Skill、不同口令
- [ ] 计划开始字段是否遵守「已有值不覆盖」(若沿用同一字段)
- [ ] 提测 / 【测试】是否交给测试 Skill本包边界清晰
---
## 12. 相关文档索引
| 主题 | 路径(仓库内) |
|---|---|
| Skill 入口 | `skills/YunxiaoPMapp/SKILL.md` |
| 交付树模型 | `skills/YunxiaoPMapp/references/model.md` |
| 交棒契约 | `skills/YunxiaoPMapp/references/handoff-contract.md` |
| 标准路径 05 | `skills/YunxiaoPMapp/references/stage-flow.md` |
| 交棒门禁 / 回退 | `skills/YunxiaoPMapp/references/handoff-and-rollback.md` |
| 描述双段 | `skills/YunxiaoPMapp/references/description-split.md` |
| 编号区块 | `skills/YunxiaoPMapp/references/workitem-ids.md` |
| 快轨 / 编号直推 | `references/fast-track.md` · `number-push.md` |
| 工时算法 | `references/work-hours.md` |
| 实写 API | `references/live-api.md` |
安装产品 Skill
```bash
npx skills add 15810879921-coder/oneos-pm-skills --skill YunxiaoPMapp -a cursor -g -y
```

View File

@@ -0,0 +1,179 @@
# 产品部流转YunxiaoPMapp到交棒为止
> 用途:先把**产品部**在云效上的工作流转说清楚;开发 / 测试 / 发版不在本 Skill 内,仅在文末标出交接点。
> 依据:`references/stage-flow.md` · `model.md` · `fast-track.md` · `handoff-contract.md`
> 日期2026-07-24
---
## 1. 产品部管到哪里
```text
产品部YunxiaoPMapp终点 = 需求状态「待开发」+【交付】负责人「何斐」
之后 = 请技术经理使用开发 Skill不建【开发】/【测试】)
```
| 谁 | 做什么 | 不做什么 |
|---|---|---|
| 产品 / YunxiaoPMapp | 建需求、打标签、建【交付】【分析】【设计】、推进状态、设计完成灌 AutoPRD、交棒 | 建【开发】【测试】、开分支、提测、发版 |
| 技术经理(接手) | 从「待开发」起拆开发 | 不改写 AutoRDO不新建第二套【交付】 |
---
## 2. 总览流程图(标准路径)
```mermaid
flowchart TB
subgraph inputs [材料入口]
Chat[聊天/录音/口述]
AutoRDO["$AutoRDO 清洗"]
Proto[原型页 Make]
end
subgraph pm [产品部 · YunxiaoPMapp]
S0["0 创建需求\n状态=待处理\n只写 AutoRDO\n不建任务"]
S1["1 受理确认\n状态=已确认\n仍不建任务"]
S2["2 分析中\n建【交付】+【分析】"]
S3["3 设计中\n建【设计】\n收口【分析】"]
S4["4 设计完成\n收口【设计】\nAutoPRD+附件\n灌【交付】描述"]
S5["5 待开发交棒\n交付负责人→何斐\n★ 产品终点"]
end
subgraph after [产品之后 · 不在本 Skill]
Dev["开发 Skill\n拆【开发】…"]
Test["测试 Skill"]
Rel["发版"]
end
Chat --> AutoRDO --> S0
Proto -.-> S4
S0 --> S1 --> S2 --> S3 --> S4 --> S5
S5 -->|"交棒契约:需求编号+交付编号"| Dev
Dev --> Test --> Rel
```
---
## 3. 各步说明(产品侧)
| 步骤 | 需求状态 | 云效任务动作 | 描述写什么 | 口令示例 |
|---|---|---|---|---|
| 0 创建 | 待处理 | 无 | `## 原始诉求AutoRDO`;编号区块待建 | `记录需求:…;推进至=暂不推进` |
| 1 受理 | 已确认 | 仍无 | 不动 | `受理确认ONEOS-xx` |
| 2 分析中 | 分析中 | 新建【交付】ASSOCIATED→需求新建【分析】TASK_SUB→交付 | 交付=占位文案 | `开始分析ONEOS-xx` |
| 3 设计中 | 设计中 | 新建【设计】TASK_SUB→交付分析计划完成=当日+阶段日历工时 | — | `开始设计ONEOS-xx交付=…;分析=…` |
| 4 设计完成 | 设计完成 | 设计完成态;需求+交付挂 ZIP/截图;交付描述换 AutoPRD | `$oneos-autoprd``## 产品说明` | `设计完成ONEOS-xx设计=…;原型=…` |
| 5 交棒 | **待开发** | **只**把【交付】负责人改为何斐 | 若仍占位须标红风险 | `交棒开发ONEOS-xx交付=…` |
**编号权威:** 需求描述 `## 工作项编号(系统)`(交付 / 分析 / 设计)。后续口令优先带 `ONEOS-xx`,禁止按标题查重。
---
## 4. 交付树(产品建出来的结构)
```mermaid
flowchart TB
REQ["产品类需求 ONEOS-R\n状态=阶段真相"]
DEL["【交付】ONEOS-a\nASSOCIATED→需求"]
AN["【分析】ONEOS-b"]
DE["【设计】ONEOS-c"]
DEL -->|"关联项 ASSOCIATED"| REQ
AN -->|"子项 TASK_SUB"| DEL
DE -->|"子项 TASK_SUB"| DEL
```
验收口诀:
- 打开【交付】→「关联项」能看到需求
- 打开【交付】→「子项」能看到分析/设计(必须 `TASK_SUB`,不能只写 parentIdentifier
---
## 5. 两条旁路(仍交到同一终点)
```mermaid
flowchart LR
subgraph standard [标准]
A1[分析中] --> A2[设计中] --> A3[设计完成] --> A4[待开发]
end
subgraph fast [无单快轨]
B1[待处理/已确认等] --> B2["待开发\n建交付+设计当日收口\n不建分析"]
end
subgraph push [编号直推]
C1[已有分析/设计编号] --> C2[收口空计划完成] --> C3[待开发+交棒何斐]
end
```
| 路径 | 何时用 | 注意 |
|---|---|---|
| 标准 0→5 | 正常产品节奏 | 设计完成才灌 AutoPRD |
| 快轨 | 明确跳过分析、急交棒 | 默认可不跑 AutoPRD交付常占位→回报标红 |
| 编号直推 | 树上已有阶段任务编号 | 不新建冗余单;只认编号 |
---
## 6. 产品部人机边界Plan 门禁)
```text
凡写云效Plan 对齐 → 人确认 → 一口气 apply → 一次校验回报
```
| 适合全自动 | 建议人点一下 |
|---|---|
| 建单、打标、建树、改状态、交棒负责人、幂等复用 | 优先级、标签、是否快轨、设计是否真可开发、占位是否接受交棒 |
---
## 7. 交棒给下游时交出什么
产品回报至少包含:
```text
【YunxiaoPMapp】
风险:(占位交棒则首行标红)
需求ONEOS-R | 状态=待开发
交付ONEOS-a | 负责人=何斐
分析ONEOS-b 或 无
设计ONEOS-c 或 快轨占位说明
下一步:请技术经理使用开发 Skill
```
下游入口条件见 `references/handoff-contract.md`:认 **需求编号 + 交付任务编号**
---
## 8. 和全链路的关系(本文件边界)
```mermaid
flowchart LR
PM[产品部本文] --> Handoff[待开发交棒]
Handoff --> Dev[开发]
Dev --> QA[测试]
QA --> Rel[发版]
```
全链路(含谢佳伟 / 时生亮)见仓库原型:
`src/prototypes/yunxiao-pipeline-handbook/`
产品 Skill 对接开发说明:
`docs-YunxiaoPMapp-实现原理-开发Skill对接.md`
---
## 9. 相关 references
| 主题 | 路径 |
|---|---|
| 标准 05 | `references/stage-flow.md` |
| 交付树 / 子项 | `references/model.md` |
| 快轨 | `references/fast-track.md` |
| 编号直推 | `references/number-push.md` |
| 交棒门禁 | `references/handoff-and-rollback.md` |
| 交棒契约 | `references/handoff-contract.md` |
| 口令 | `references/commands.md` |
---
## 延伸阅读
- 四角色泳道(产品/开发/测试/发版):`docs-四角色泳道流程图.md`
- 开发侧草案:`docs-开发侧流转草案.md`

View File

@@ -0,0 +1,318 @@
# 全流程分步说明:产品 → 开发 → 测试 → 发版
> 把整条链路拆成**按顺序执行的步骤**,每步说清:谁做、做什么、云效上变成什么、下一步谁接。
> 读完应能照着口令/动作走完一轮(标准路径)。
> 日期2026-07-24
---
## 先记住三件事
1. **需求状态 = 阶段真相**
看需求状态就知道现在卡在哪一段(分析中 / 待开发 / 开发中 / 待测试…)。
2. **每条需求只有 1 个【交付】容器**
分析、设计、开发、测试都挂在这个交付下面(子项),不要再建第二个【交付】。
3. **编号说话,不靠标题查**
口令尽量带 `ONEOS-xx`;改标题不影响关联。
```text
需求(状态主轴)
└─【交付】(容器,关联到需求)
├─【分析】【设计】 ← 产品建
├─【开发】… ← 开发建
└─【测试】 ← 开发提测时建
【发版】另建,挂迭代 + 范围内需求
```
---
## 总步骤一览(共 18 步)
| 阶段 | 步骤 | 一句话 |
|---|---|---|
| **产品** | 16 | 从记诉求到交棒给何斐 |
| **开发** | 712 | 从拆任务到提测 |
| **测试** | 1315 | 从接测到测试完成 |
| **发版** | 1617 | 从建发版到发布结果 |
| **收口** | 18 | 产品验收关闭 |
---
## 阶段 A产品步骤 16
### 步骤 1记录需求
| | |
|---|---|
| **谁** | 产品 / AIYunxiaoPMapp |
| **做什么** | 把聊天、录音、口述先洗成 AutoRDO再建一条**产品类需求** |
| **需求状态** | **待处理** |
| **云效任务** | 不建任何任务 |
| **描述里写** | `## 原始诉求AutoRDO`;编号区先空着 |
| **口令例** | `记录需求:…;推进至=暂不推进` |
| **为什么** | 先落盘,避免口头需求丢;还没确认值不值得做 |
---
### 步骤 2受理确认
| | |
|---|---|
| **谁** | 产品 |
| **做什么** | 确认要做:定优先级、打标签(从云效标签里点选) |
| **需求状态** | **已确认** |
| **云效任务** | 仍不建任务 |
| **口令例** | `受理确认ONEOS-xx` |
| **为什么** | 和「还没想清楚」的待处理分开;确认后才进分析/设计 |
---
### 步骤 3开始分析
| | |
|---|---|
| **谁** | 产品 / AI |
| **做什么** | ① 建 **【交付】**(整条需求的唯一容器,关联到需求)② 建 **【分析】**(挂在交付**子项**下) |
| **需求状态** | **分析中** |
| **云效任务** | 【交付】+【分析】 |
| **口令例** | `开始分析ONEOS-xx` |
| **验收** | 打开【交付】→「关联项」有需求;「子项」有【分析】 |
| **为什么** | 分析要有落点;后续设计/开发/测试都挂同一棵树 |
---
### 步骤 4开始设计
| | |
|---|---|
| **谁** | 产品 / AI |
| **做什么** | 建 **【设计】**(子项挂交付);收口【分析】计划时间 |
| **需求状态** | **设计中** |
| **云效任务** | 新增【设计】 |
| **口令例** | `开始设计ONEOS-xx交付=…;分析=…` |
| **为什么** | 进入原型/方案设计;分析阶段收口 |
---
### 步骤 5设计完成
| | |
|---|---|
| **谁** | 产品 / AI |
| **做什么** | 收口【设计】;跑 AutoPRD把**产品说明**灌进【交付】描述;挂原型 ZIP/截图等附件 |
| **需求状态** | **设计完成** |
| **口令例** | `设计完成ONEOS-xx设计=…;原型=…` |
| **为什么** | 开发接手时看的是【交付】里的产品说明,不是聊天记录 |
---
### 步骤 6交棒开发产品终点
| | |
|---|---|
| **谁** | 产品 / AI |
| **做什么** | 需求改为待开发;**【交付】负责人改为何斐**(不新建开发/测试任务) |
| **需求状态** | **待开发** ★ |
| **交出什么** | 需求编号 +【交付】编号 |
| **口令例** | `交棒开发ONEOS-xx交付=…` |
| **为什么** | 产品部到此结束;技术经理从这里拆开发 |
> 旁路:急单可用**快轨**(跳过分析、直接待开发),仍交到同一终点「待开发 + 交付→何斐」。
---
## 阶段 B开发步骤 712
### 步骤 7分配开发任务
| | |
|---|---|
| **谁** | 开发主管何斐 / 开发 Skill |
| **做什么** | 输入**交付任务编号** → 自动建 **【开发】**;标题=`【开发】`+需求标题;**描述人工补**;指定开发人;自动写计划时间 |
| **关联** | 子项挂【交付】;关联项挂需求 |
| **需求状态** | 仍为 **待开发**(确认即可,一般不用再改) |
| **口令例** | `分配任务:交付=ONEOS-a开发人=张三` |
| **为什么** | 一条需求可拆多个开发任务;都挂在同一交付下 |
---
### 步骤 8开始开发
| | |
|---|---|
| **谁** | 开发人员 |
| **做什么** | 口令带上**开发任务编号** |
| **开发任务** | → **处理中** |
| **需求状态** | → **开发中** |
| **口令例** | `开始开发ONEOS-d` |
| **为什么** | 看板一眼能看出「正在写代码」 |
---
### 步骤 9写代码 / 提 MR
| | |
|---|---|
| **谁** | 开发人员 |
| **做什么** | 按【交付】里的产品说明实现;分支/MR 建议挂上开发任务编号与需求编号 |
| **需求状态** | 仍为 **开发中** |
| **为什么** | 代码可追溯到哪条开发任务、哪条需求 |
---
### 步骤 10AI 自测门禁(开发侧草案)
| | |
|---|---|
| **谁** | AI开发完成后触发 |
| **做什么** | 找与**需求同标题**的测试计划 → 按用例自测 → 不过则自动提缺陷(标题含开发任务编号)并尝试修复,直到本计划用例全过 |
| **需求状态** | 仍为 **开发中**(未全过前) |
| **为什么** | 在正式提测前先挡住明显问题(属草案,规则可再收紧) |
---
### 步骤 11开发任务完成
| | |
|---|---|
| **谁** | 系统 / AI用例全过之后 |
| **做什么** | 该条【开发】标为**已完成** |
| **需求状态** | → **开发完成**(若有多条开发,建议等**全部**完成再改,避免过早) |
| **为什么** | 标记「代码+门禁」这一段结束 |
---
### 步骤 12完成开发 · 正式提测
| | |
|---|---|
| **谁** | 开发人员(自测也完成) |
| **做什么** | 口令「完成开发」→ 自动建 **【测试】**(标题=`【测试】`+任务名);子项挂【交付】;建议再关联需求;指派测试(如谢佳伟) |
| **需求状态** | → **待测试** ★ |
| **口令例** | `完成开发ONEOS-d` |
| **为什么** | 开发交棒给测试;测试侧开始接单 |
---
## 阶段 C测试步骤 1315
### 步骤 13接测试任务
| | |
|---|---|
| **谁** | 测试(谢佳伟等) |
| **做什么** | 打开【测试】任务;确认关联的需求与交付;准备/核对测试计划与用例包(建议按**需求编号**分包,比「同标题」更稳) |
| **需求状态** | **待测试** → 开始执行后改为 **测试中** |
| **为什么** | 正式测试以计划用例为准,不靠口头「测过了」 |
---
### 步骤 14执行用例 · 缺陷回流
| | |
|---|---|
| **谁** | 测试执行;失败时回流开发修 |
| **做什么** | 按用例执行;失败建缺陷 → 开发修复 → 再测 |
| **需求状态** | **测试中** |
| **为什么** | 质量关口;未绿不能进发版 |
---
### 步骤 15测试完成
| | |
|---|---|
| **谁** | 测试 / AI 辅助判定 |
| **做什么** | **本需求**相关用例全绿 →【测试】收口;通知发版对接人 |
| **需求状态** | → **测试完成** ★ |
| **注意** | 只卡本需求,不卡同迭代里别的需求 |
| **为什么** | 发版范围以「测试完成」的需求为准 |
---
## 阶段 D发版步骤 1617
### 步骤 16建发版任务
| | |
|---|---|
| **谁** | 发版对接人(时生亮)· 手工或 AI |
| **做什么** | 建 **【发版】**;关联**迭代** + 本期内要上的需求(建议再挂交付/测试);汇总更新说明 |
| **需求状态** | 进入发布流程时 → **发布中** |
| **为什么** | 一次发版可能含多条需求;要有明确范围清单 |
---
### 步骤 17发布结果回写
| | |
|---|---|
| **谁** | 发版对接人 / 流水线 |
| **做什么** | 执行发布 |
| **结果** | 成功 → **发布完成**;失败 → **发布失败**(可重试再进发布中) |
| **为什么** | 成败要回写云效,避免「以为发了其实没发」 |
---
## 阶段 E收口步骤 18
### 步骤 18业务验收 · 关闭
| | |
|---|---|
| **谁** | 产品 |
| **做什么** | 业务验收通过后,关闭需求,并收口【交付】 |
| **需求状态** | → **已关闭** |
| **为什么** | 全链路结束;树上任务与需求一致收口 |
---
## 状态主链(串起来看)
```text
待处理 → 已确认 → 分析中 → 设计中 → 设计完成
→ 待开发 ← 产品交棒给何斐
→ 开发中 → 开发完成
→ 待测试 → 测试中 → 测试完成
→ 发布中 → 发布完成(或发布失败可重试)
→ 已关闭 ← 产品验收关单
```
---
## 四个交棒口(最重要)
| 交棒 | 交出人 | 接棒人 | 交出物 | 状态落点 |
|---|---|---|---|---|
| ① 产品→开发 | 产品 | 何斐 | 需求号 + 交付号 | 待开发 |
| ② 开发→测试 | 开发人 | 测试 | 【测试】任务已建好 | 待测试 |
| ③ 测试→发版 | 测试 | 发版 | 本需求用例全绿 | 测试完成 |
| ④ 发版→产品 | 发版 | 产品 | 发布完成 / 更新说明 | 发布完成 → 已关闭 |
---
## 谁在什么时候动(对照表)
| 步骤 | 产品 | 开发主管 | 开发人 | 测试 | 发版 |
|---|---|---|---|---|---|
| 12 记需求/确认 | ● | | | | |
| 35 分析设计 | ● | | | | |
| 6 交棒 | ● | 接 | | | |
| 7 分配任务 | | ● | | | |
| 89 开始写码 | | | ● | | |
| 1011 AI门禁/完成任务 | | | ●/AI | | |
| 12 提测 | | | ● | 接 | |
| 1315 测试 | | | 修缺陷 | ● | |
| 1617 发版 | | | | | ● |
| 18 关闭 | ● | | | | |
---
## 相关文档
| 文档 | 用途 |
|---|---|
| `docs-四角色泳道流程图.md` | 泳道图总览 |
| `docs-产品部流转流程图.md` | 产品 16 细规 |
| `docs-开发侧流转草案.md` | 开发 712 细规与待拍板 |
| `yunxiao-pipeline-handbook` | 云效规则与配置 |

View File

@@ -0,0 +1,181 @@
# 四角色泳道图:产品 · 开发 · 测试 · 发版
> 用途:一张图看清从建需求到发版关闭,四条泳道各自做什么、在哪交棒。
> 依据:产品部流转 · 开发侧草案 · 生产线手册(测试/发版)
> 日期2026-07-24
> 说明开发泳道含「AI 用例门禁」草案;测试泳道为正式提测后的人/计划执行。
---
## 1. 泳道总览(推荐主图)
```mermaid
flowchart TB
subgraph PM["泳道① 产品"]
direction TB
P0["建需求 · 待处理<br/>只写 AutoRDO"]
P1["受理确认 · 已确认"]
P2["分析中<br/>建【交付】+【分析】"]
P3["设计中<br/>建【设计】"]
P4["设计完成<br/>AutoPRD 灌交付"]
P5["交棒 · 待开发<br/>交付负责人→何斐"]
P6["业务验收后<br/>关闭需求+交付"]
P0 --> P1 --> P2 --> P3 --> P4 --> P5
end
subgraph DEV["泳道② 开发"]
direction TB
D1["何斐:分配任务<br/>建【开发】SUB→交付"]
D2["开发人:开始开发<br/>任务处理中 · 需求开发中"]
D3["写代码 / 提 MR"]
D4["AI 按同标题测试计划自测<br/>不过→提缺陷并修"]
D5["开发任务已完成<br/>需求→开发完成"]
D6["完成开发(含自测)<br/>建【测试】· 需求待测试"]
D1 --> D2 --> D3 --> D4 --> D5 --> D6
end
subgraph QA["泳道③ 测试"]
direction TB
T1["接【测试】任务<br/>需求=待测试"]
T2["建/挂测试计划与用例<br/>(建议按需求编号分包)"]
T3["测试中 · 执行用例"]
T4["缺陷回流开发修复"]
T5["本需求用例全绿<br/>需求→测试完成"]
T1 --> T2 --> T3
T3 -.->|失败| T4
T4 -.->|再测| T3
T3 -->|通过| T5
end
subgraph REL["泳道④ 发版"]
direction TB
R1["建【发版】任务<br/>挂迭代+范围内需求"]
R2["汇总更新说明"]
R3["发布中"]
R4{"发布结果"}
R5["发布完成"]
R6["发布失败 · 可重试"]
R1 --> R2 --> R3 --> R4
R4 -->|成功| R5
R4 -->|失败| R6
R6 -.-> R3
end
P5 -->|"交棒契约<br/>需求编号+交付编号"| D1
D6 -->|"提测<br/>【测试】已挂交付"| T1
T5 -->|"交棒发版"| R1
R5 -->|"业务可验收"| P6
```
---
## 2. 横向时间轴版(谁在哪一阶段动)
从左到右是需求状态主链;上下是四个角色。空格表示该角色此阶段无主动动作。
```mermaid
flowchart LR
subgraph S_PM["产品阶段"]
direction TB
sp0["待处理→已确认"]
sp1["分析/设计/设计完成"]
sp2["待开发交棒"]
sp3["已关闭"]
end
subgraph S_DEV["开发阶段"]
direction TB
sd0["拆【开发】"]
sd1["开发中"]
sd2["AI门禁→开发完成"]
sd3["建【测试】→待测试"]
end
subgraph S_QA["测试阶段"]
direction TB
sq0["待测试"]
sq1["测试中"]
sq2["测试完成"]
end
subgraph S_REL["发版阶段"]
direction TB
sr0["建【发版】"]
sr1["发布中"]
sr2["完成/失败"]
end
sp0 --> sp1 --> sp2
sp2 --> sd0 --> sd1 --> sd2 --> sd3
sd3 --> sq0 --> sq1 --> sq2
sq2 --> sr0 --> sr1 --> sr2
sr2 --> sp3
```
---
## 3. 交接点一览
| # | 从 → 到 | 交出什么 | 需求状态落点 |
|---|---|---|---|
| 1 | 产品 → 开发 | 需求编号 +【交付】编号;交付负责人=何斐 | **待开发** |
| 2 | 开发 → 测试 | 【测试】任务(子项挂交付);用例计划可先备好 | **待测试** |
| 3 | 测试 → 发版 | 本需求用例全绿;范围内需求清单 | **测试完成** |
| 4 | 发版 → 产品 | 发布完成证据 / 更新说明 | **发布完成** → 产品关单 **已关闭** |
---
## 4. 各泳道职责边界(一句话)
| 角色 | 管什么 | 不管什么 |
|---|---|---|
| **产品** | 建需求、【交付】【分析】【设计】、AutoPRD、交棒待开发、验收关闭 | 不建【开发】【测试】【发版】、不开分支 |
| **开发** | 拆【开发】、写码、AI 自测门禁、建【测试】提测 | 不改写产品 AutoRDO不建第二套【交付】 |
| **测试** | 接【测试】、跑计划用例、缺陷回流、判测试完成 | 不擅自改需求状态到开发中;不建【发版】(可催) |
| **发版** | 建【发版】、挂迭代与范围、发布与回写成败 | 不替代测试判绿;不关闭需求(交给产品) |
---
## 5. 云效工作项树(跨角色)
```mermaid
flowchart TB
REQ["需求 · 状态=阶段真相"]
DEL["【交付】ASSOCIATED→需求"]
AN["【分析】"]
DE["【设计】"]
DV["【开发】"]
TE["【测试】"]
RE["【发版】ASSOCIATED→迭代/需求"]
DEL --> REQ
AN -->|TASK_SUB| DEL
DE -->|TASK_SUB| DEL
DV -->|TASK_SUB| DEL
TE -->|TASK_SUB| DEL
DV -.->|ASSOCIATED| REQ
TE -.->|ASSOCIATED| REQ
RE -.->|关联范围| REQ
```
---
## 6. 典型负责人(手册约定,可按项目改)
| 泳道 | 典型对接人 |
|---|---|
| 产品 | 王冕 · YunxiaoPMapp / AI |
| 开发 | 何斐(拆任务)→ 王雨昊 / 李振等(执行) |
| 测试 | 谢佳伟 |
| 发版 | 时生亮 |
---
## 相关文档
| 文档 | 说明 |
|---|---|
| `docs-全流程分步说明.md` | **整条链路逐步说明(推荐先读)** |
| `docs-产品部流转流程图.md` | 产品 0→5 细图 |
| `docs-开发侧流转草案.md` | 开发 D1D5 细图 |
| `yunxiao-pipeline-handbook` | 全链路配置与规则 |

View File

@@ -0,0 +1,230 @@
# 开发侧流转草案(产品交棒之后)
> 来源产品经理口述规则整理2026-07-24
> 上游终点:产品部 `docs-产品部流转流程图.md` → 需求=**待开发**,【交付】负责人=**何斐**
> 本文件目标:把「何斐拆任务 → 开发执行 → AI 用例门禁 → 提测」画清,供后续 **YunxiaoDevapp** Skill 定稿
> 状态:**草案**(文末有待拍板项)
---
## 1. 总览流程图
```mermaid
flowchart TB
subgraph handoff [产品已交棒]
Ready["需求=待开发\n【交付】负责人=何斐"]
end
subgraph d1 [D1 分配开发]
Assign["何斐:分配任务 + 交付任务编号"]
CreateDev["自动建【开发】+需求标题\n描述人工补\n指定开发人\n写计划时间"]
Link["子项 TASK_SUB→交付\n关联项 ASSOCIATED→需求"]
StReady["需求保持/确认为 待开发"]
end
subgraph d2 [D2 开始开发]
Start["开发人:开始开发 + 开发任务编号"]
DevDoing["开发任务→处理中"]
ReqDoing["需求→开发中"]
end
subgraph d3 [D3 AI 用例门禁]
CodeDone["代码开发完成触发"]
FindPlan["按需求同标题找测试计划"]
AITest["AI 按用例自测"]
Fail["未通过→自动提缺陷\n标题含开发任务编号\nAI 写标题描述"]
Fix["自动修复→再测"]
PassGate["用例全部通过"]
end
subgraph d4 [D4 开发任务完成]
DevDone["该条【开发】→已完成"]
ReqDevDone["需求→开发完成"]
end
subgraph d5 [D5 完成开发·提测]
Finish["开发人:完成开发\n含自测完成"]
CreateTest["自动建【测试】+任务名\n子项→交付"]
PendingTest["需求→待测试"]
end
Ready --> Assign --> CreateDev --> Link --> StReady
StReady --> Start --> DevDoing --> ReqDoing
ReqDoing --> CodeDone --> FindPlan --> AITest
AITest -->|未通过| Fail --> Fix --> AITest
AITest -->|全通过| PassGate --> DevDone --> ReqDevDone
ReqDevDone --> Finish --> CreateTest --> PendingTest
```
---
## 2. 分步说明(按你的 5 条)
### D1何斐分配任务
| 项 | 规则 |
|---|---|
| 触发 | Skill 口令:`分配任务` + **交付任务编号** |
| 新建 | 【开发】任务;标题 = `【开发】` + **需求标题** |
| 描述 | **人工添加**Skill 不代写正文,或只留空模板) |
| 负责人 | 口令指定开发人员 |
| 计划时间 | **自动创建**计划开始/计划完成(算法待定:阶段日历工时 or 人力预估,见待拍板) |
| 关联 | **子项** `TASK_SUB` →【交付】;**关联项** `ASSOCIATED` → 需求 |
| 需求状态 | 改为 / 确认为 **待开发**(见待拍板:与产品交棒是否重复) |
### D2开始开发
| 项 | 规则 |
|---|---|
| 触发 | `开始开发` + **开发任务编号** |
| 开发任务 | → **处理中** |
| 需求 | → **开发中**(有 ≥1 条开发进入处理中即可,或本条触发即改,见待拍板) |
### D3代码完成后 · AI 按测试计划自测
| 项 | 规则 |
|---|---|
| 触发 | 「代码开发完成」MR 合并 / 口令 / Webhook触发源待定 |
| 找计划 | **自动寻找与需求同标题的测试计划** |
| 执行 | AI 按该计划中用例自行测试 |
| 失败 | 自动提缺陷:标题含 **开发任务编号** + AI 生成标题/描述;再自动修复,循环直到用例全过 |
### D4用例全通过
| 项 | 规则 |
|---|---|
| 该条【开发】 | → **已完成** |
| 需求 | → **开发完成** |
### D5开发人「完成开发」自测也完成
| 项 | 规则 |
|---|---|
| 触发 | `完成开发` +(建议带)开发任务编号 |
| 新建 | 【测试】任务;标题 = `【测试】` + 任务名称(建议=需求标题) |
| 关联 | 子项 →【交付】(建议同时 ASSOCIATED→需求 |
| 需求 | → **待测试** |
---
## 3. 与产品部的衔接
```mermaid
flowchart LR
PM["产品 YunxiaoPMapp\n待开发 + 交付→何斐"] --> DevSkill["开发 Skill 草案\n本文 D1D5"]
DevSkill --> QA["测试执行人/Skill\n待测试之后"]
```
| 上游已具备 | 开发侧依赖 |
|---|---|
| 需求编号 +【交付】编号 | D1 入口只认编号,不按标题拆第二套交付 |
| 交付 ASSOCIATED→需求 | D1 开发任务再 ASSOCIATED→需求、SUB→交付 |
| 产品不建【开发】【测试】 | 仅开发 Skill 建这两类 |
---
## 4. 待拍板(建议你先定这几条)
### 4.1 状态顺序是否自洽
你现在的顺序是:
```text
D3 AI 用例全过 → 开发任务已完成 + 需求「开发完成」
D5 完成开发 → 建【测试】+ 需求「待测试」
```
与现有手册常见顺序对比:
```text
手册常见:开发人完成自测 → 待测试 →(测试执行)→ 测试完成
你草案: AI 先跑测试计划用例过关 → 开发完成 → 人再点完成开发 → 待测试
```
需要确认:
1. D3 的「测试计划」是 **开发自测门禁**,正式【测试】任务仍留给谢佳伟?
2. 还是 D3 已等同正式测试,那 D5 再建【测试】是否重复?
### 4.2 「需求→待开发」写在 D1
产品交棒时需求**已经是待开发**。D1 再改一次通常多余。建议改为:
- D1 **校验**需求已是待开发;若不是则停下或只允许从设计完成快轨补交棒
- 有开发任务进入处理中时,需求才变为 **开发中**(即你的 D2
### 4.3 「与需求同标题的测试计划」
标题易改、易撞名。更稳的是:
- 测试计划关联 **需求编号 / 迭代**,或
- 用例包命名 `CP-{需求编号}-…`
否则同名需求/改标题会导致找错计划。
### 4.4 AI 自动提缺陷并自动修复
风险高:无上限循环、误报、改回旧逻辑。建议门禁:
- 最多 N 轮;失败转人工
- 缺陷必须关联 **开发任务编号 + 需求编号 + 用例 ID**
- 与「防回归」清单联动,禁止静默改无关模块
### 4.5 多条【开发】时需求状态
| 场景 | 建议 |
|---|---|
| 任一条开始开发 | 需求 → 开发中 |
| 需求 → 开发完成 | **全部**未取消【开发】均为已完成(与手册 Y21 一致) |
| 需求 → 待测试 | 全部【开发】完成后,由末位「完成开发」或系统自动建【测试】 |
你原文 D4 写「该条」通过就把需求改成开发完成——多开发人并行时会过早。建议改成「全员开发任务完成」。
### 4.6 关联写法(与产品侧一致)
同一 create 只能带一条 `createWorkitemRelationInfo`
- 优先保证【开发】/【测试】**子项挂在交付**(交付详情「子项」可见)
- ASSOCIATED→需求若同 create 互斥,需约定:先 SUB再补 ASSOCIATED或 OpenAPI 双挂
---
## 5. 建议口令面(草案)
```text
分配任务:交付任务=ONEOS-a开发人=张三,李四;计划开始=…;计划完成=…
开始开发:开发任务=ONEOS-d
代码完成:开发任务=ONEOS-d → 触发 AI 用例门禁(或 Webhook
完成开发:开发任务=ONEOS-d → 建【测试】;需求→待测试
```
---
## 6. 推荐定稿后的状态主链(供你勾选)
**方案 A贴近你原文AI 测作开发门禁)**
```text
待开发 → 开发中 →AI 用例门禁)→ 开发完成 → 待测试 → 测试中 → 测试完成 → …
```
**方案 B贴近现有生产线手册**
```text
待开发 → 开发中 → 开发完成(人自测+MR→ 待测试 → 测试中(人/AI 跑计划)→ 测试完成 → …
```
AI 跑测试计划放在 **待测试之后**,与【测试】任务负责人(如谢佳伟)对齐。
---
## 7. 下一步
1. 你拍板:**方案 A 或 B**,以及多【开发】时「开发完成 / 待测试」的聚合规则
2. 我按定稿输出 `YunxiaoDevapp``SKILL.md` 骨架 + 与产品交棒契约对齐段落
3. 再补一版「仅开发侧」验收清单10 条以内)
---
## 相关文档
| 文档 | 路径 |
|---|---|
| 产品部流转 | `docs-产品部流转流程图.md` |
| 产品↔开发契约 | `docs-YunxiaoPMapp-实现原理-开发Skill对接.md` |
| 全链路手册 | `src/prototypes/yunxiao-pipeline-handbook/` |

View File

@@ -0,0 +1,47 @@
# 无单快轨到待开发
适用:口令明确「快轨」或「推进至待开发」且当前需求尚无标准分析路径任务(或用户确认跳过分析)。
## 动作表
| 对象 | 动作 |
|---|---|
| 需求 | 状态 → **待开发****预计工时=2**、**实际工时=2**(覆盖同日 8h 日历工时默认);标签按口令;更新编号区块 |
| 【交付】 | 无则新建ASSOCIATED→需求勿用 PARENT负责人→何斐**计划开始=创建当日**`79`**不写**计划完成;**描述双路径**(见下);**标签与需求相同**;更新编号区块 |
| 【设计】 | **必须新建****TASK_SUB→交付**(交付「子项」须可见);**描述=复制需求当前描述正文**;计划开始/完成均=当日create 后 `field/value``79`+`80`);任务→完成态;**标签与需求相同**;建后再尝试 **ASSOCIATED→原始需求**Cookie 常失败,见 live-api失败须标红**子项优先于关联项**);更新编号区块 |
| 【分析】 | **禁止创建** |
## 交付描述双路径A1
| 口令/材料 | 【交付】描述 |
|---|---|
| **手工描述**(无指定原型) | 同步需求当前手工/AutoRDO 正文(与设计一致可复制 document |
| **指定原型页面** | 调用 `$oneos-autoprd`,从原型生成 AutoPRD「产品说明」写入【交付】 |
| 既无手工可同步正文、又无原型 | 才允许占位 `等待设计任务完成后自动填入`Plan 勾选交棒占位风险,回报首行标红 |
有手工或原型时**禁止**交棒占位。
## AutoPRD
- 快轨默认可不跑 AutoPRD**例外**:口令指定原型 → 交付走 AutoPRD 路径(上表)。
- 口令同时「设计完成 + 原型」时仍按步骤 4 灌需求产品说明段。
## 查重
只认任务编号。已有分析单不得因「快轨」被删除。
## 回报必含
- 需求 / 交付 / 设计编号
- 「快轨:未建分析;设计已同步需求描述并当日收口」
- 交付描述来源:手工同步 / AutoPRD / 占位(若占位则首行标红)
- 需求预计工时=2、实际工时=2
- 设计关联项含需求编号;交付子项含设计编号
## 与标准 / 编号直推对比
```text
标准:分析中→交付+分析 → 设计中→设计+收口分析 → 设计完成→收口设计 → 待开发交棒
快轨(无既有阶段单):→ 待开发:新建交付+设计+交棒何斐(无分析;设计当日收口;需求工时 2+2
编号直推:已有分析/设计编号 → 收口空计划完成 → 待开发+交付交棒(不新建冗余单)
```

View File

@@ -0,0 +1,242 @@
# 云效实写 APIYunxiaoPMapp 已验证)
`verified_at`: 2026-07-25 · **项目须门禁 PJ 点选**(见 [project-selection.md](project-selection.md));历史验证样本项目为 `01_ONEOS` / 原「统一运营管理平台」(`last_selected.spaceIdentifier``assets/runtime-ids.json`,禁止未点选即使用)。
本文件只记**已跑通**的写法;禁止再盲试 `updateStatus` / 错误 `updateFieldValue` POST。
## 认证
- CookieChrome 域 `.aliyun.com` / `devops.aliyun.com``browser_cookie3` 或 Playwright storage
- Header`x-xsrf-token` = cookie `XSRF-TOKEN`URL 解码后)
- `Origin` / `Referer``https://devops.aliyun.com`
## 建单
`POST|PUT /projex/api/workitem/workitem?_input_charset=utf-8`
创建响应 `result.identifier` / `serialNumber` 即编号真相;**禁止按标题查重**。
## 改负责人(已通)
```http
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
{"propertyKey":"assignedTo","propertyValue":"<userId>","operateType":"COVER"}
```
交棒:【交付】`propertyValue` = 何斐 ID。
## 打标签(已通)
```http
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
{"workitemIdentifier":"{id}","propertyKey":"tag","propertyValue":"<tagId>[,<tagId>]","operateType":"COVER"}
```
## 改状态(已通 · 唯一推荐)
```http
POST /projex/api/workitem/workitem/{id}/status/transit?_input_charset=utf-8
{"fromStatus":"<status.identifier>","toStatus":"<status.identifier>"}
```
成功:`code=200``result=true`。失败时 `errorMsg` 含「不能流转」。
### 需求状态 ID本项目
| 显示名 | identifier |
|---|---|
| 待处理 | `100005` |
| 已确认 | `32` |
| 分析中 | `154395` |
| 设计中 | `156603` |
| 设计完成 | `307012` |
| 待开发 | `1582fc929d429111b925309493` |
### 任务状态 ID
| 显示名 | identifier |
|---|---|
| 待处理 | `100005` |
| 已完成 | `100014` |
### 极速交棒跳转(工作流允许)
从「待处理」菜单可见直达「设计完成」;推荐最少跳:
```text
待处理 → 设计完成 → 待开发
```
标准路径若需看板留痕,可走完整链:已确认→分析中→设计中→设计完成→待开发(仍用本 API勿开 UI
### 禁止(已证伪)
| 写法 | 结果 |
|---|---|
| `PATCH …/updateStatus` + `statusIdentifier` | `400 不能为空` |
| `PATCH …/{id}` + `propertyKey=status` | `property not found` |
| Playwright 点左侧/列表上的状态色块(`x<1100` | 假成功、状态不落库 |
仅当 `status/transit` 不可用时,才用 UI右侧详情状态钮`getBoundingClientRect().x > 1100`+ `.next-menu-item`
## 计划开始/完成 · 提交部门/人 · 预计工时2026-07-27 修订)
**通用字段写入(已通):**
```http
POST /projex/api/workitem/workitem/field/value/{workitemId}?_input_charset=utf-8
Content-Type: application/x-www-form-urlencoded
fieldValueList=[{"fieldIdentifier":"79","value":"2026-07-27 12:00:00"},{"fieldIdentifier":"3132597a9718d1c282b7ba5a0c","value":""},{"fieldIdentifier":"9e01269e96f91fbb97d36bf5b3","value":""}]
```
| 字段 | fieldIdentifier | value |
|---|---|---|
| 计划开始 | `79` | `YYYY-MM-DD HH:mm:ss`(推荐正午)或 epoch ms 字符串 |
| 计划完成 | `80` | 同上 |
| 提交部门 | `3132597a9718d1c282b7ba5a0c` | 纯文本 |
| 提交人 | `9e01269e96f91fbb97d36bf5b3` | 纯文本 |
**预计工时 `101586`:禁止直接改字段**(报「不可直接修改」)。须登记:
```http
POST /projex/api/workitem/workitem/time/estimate?_input_charset=utf-8
{"workitemIdentifier":"<id>","spentTime":8,"type":"develop","description":"","recordUserIdentifier":"<userId>","forCreate":false,"containsRestDay":false}
```
删除多余预估:`DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}`
列表:`GET …/time/estimate/list?workitemIdentifier=`
旧写法 `PATCH …/updateWorkitemFieldValue` 对上述自定义字段常 `400 不能为空`,勿再优先使用。
## 父子 / 子项 / 关联项(已通 · 2026-07-23 修订 · 子项优先)
### 关联项(【交付】强制 · ASSOCIATED
任务详情「关联项」只认 `ASSOCIATED`。**仅【交付】**建单时 `createWorkitemRelationInfo` 必须指向**需求**
```json
{
"createWorkitemRelationInfo": {
"relatedWorkitemIdentifier": "<需求id>",
"relatedToRelationIdentifier": "ASSOCIATED"
}
}
```
校验:
```http
GET /projex/api/workitem/v2/workitem/{id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
```
`result` 含该需求即通过。
### 禁止(关联项)
| 写法 | 结果 |
|---|---|
| `relatedToRelationIdentifier=PARENT` 把交付挂需求 | 详情可能有 parent**关联项仍为空** |
| 分析/设计只用 `ASSOCIATED→需求` + `parentIdentifier` | 关联项可能有,**交付子项仍为空**ONEOS-246/247 |
| 建后再 `POST …/relation/record` 补关系 | Cookie 路径下常报「不能关联相同的工作项」 |
| `createWorkitemRelationList` | 不落 ASSOCIATED |
### 子项(【分析】/【设计】强制 · TASK_SUB
「子项」页读 `PARENT_SUB` / `TASK_SUB`,分析/设计**必须**
```json
{
"parent": "<交付id>",
"parentIdentifier": "<交付id>",
"createWorkitemRelationInfo": {
"relatedWorkitemIdentifier": "<交付id>",
"relatedToRelationIdentifier": "TASK_SUB"
}
}
```
同一 create 只能带一条 `createWorkitemRelationInfo`
`ASSOCIATED→需求``TASK_SUB→交付` **不能同时写**
**产品优先级交付「子项」tab > 阶段任务「关联项」。**
交付本身仍必须 `ASSOCIATED→需求`。标准路径下分析/设计的「关联项」允许为空。
**无单快轨例外(设计双挂):** create 用 `TASK_SUB→交付` 后,须再补 **ASSOCIATED→原始需求**,使设计详情「关联项」可见需求。
```http
POST /projex/api/workitem/workitem/{id}/relation/record?_input_charset=utf-8
{"relationIdentifier":"ASSOCIATED","toWorkitemIdentifier":"<id>"}
```
**已证伪Cookie · 2026-07-27** 凡工作项**已创建**后再 `relation/record` 补挂(含 ASSOCIATED / TASK_SUB常报「不能关联相同的工作项」与是否已有父项无关。`createWorkitemRelationList` 亦不落 ASSOCIATED。
**可行路径:**
| 目标 | 做法 |
|---|---|
| 交付「子项」可见设计(优先) | create 带 `TASK_SUB→交付` |
| 设计「关联项」可见需求 | create 带 `ASSOCIATED→需求`(与上互斥,同 create 只能一条) |
| 双挂 | 需个人 `x-yunxiao-token` OpenAPICookie 路径**不得**声称成功 |
产品默认:**子项优先**;关联项失败须在回报中标红并列出缺项。
校验子项:
```http
GET /projex/api/workitem/v2/workitem/{id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true
```
结果须含对应分析/设计 identifier。
校验设计关联项:
```http
GET /projex/api/workitem/v2/workitem/{id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
```
`result` 须含原始需求 identifier。
### 无单快轨字段默认2026-07-27
| 对象 | 规则 |
|---|---|
| 【设计】描述 | 复制需求 document HTML |
| 【设计】`79`/`80` | 当日 `12:00:00` / `23:59:59`create 后 `field/value`(勿 create 同时带 79+80 |
| 【交付】描述 | 手工同步需求正文或原型→AutoPRD禁止无故占位 |
| 【交付】`79` | 创建当日;不写 `80` |
| 【交付】/【设计】标签 | 与需求相同,`PATCH propertyKey=tag` |
| 需求预计工时 | `time/estimate` **spentTime=2**(先删多余预估) |
| 需求实际工时 | `POST …/workitem/time`body 用 **`actualTime`**(非 spentTime+ `gmtStart`/`gmtEnd` epoch ms 字符串;见 `runtime-ids.json` `fields.actual_hours` |
| 描述更新 | `PATCH …/workitem/{id}/document``{"content":"<html>","formatType":"RICHTEXT"}` |
## 迭代挂接(已通 · 2026-07-27 · 只挂交付)
创建迭代:`POST /projex/api/workspace/sprint`(必填 `staffIds`;可写 `capacityHours`)。
挂【交付】到迭代:
```http
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
{"workitemIdentifier":"{id}","propertyKey":"sprint","propertyValue":"{sprintId}","operateType":"COVER"}
```
清空误挂(如需求):`propertyValue:""` + `operateType:"COVER"`
**校验**必须读 `/extra`(详情主接口常不含 sprint 字段,禁止据此判失败):
```http
GET /projex/api/workitem/workitem/{id}/extra?_input_charset=utf-8
result.sprint[].identifier / name
```
产品规则:**只挂【交付】**;需求 / 分析 / 设计默认不挂(除非口令显式)。
### 极速建单注意
1. Cookie 只刷一次;全程纯 HTTP默认**不开浏览器**。
2. 交付建完后,【分析】与【设计】**并行**创建(均 TASK_SUB→交付标准/快轨两树可并行。
3. 状态用 `transit` + **本地追踪 fromStatus**(禁止每次 GET负责人在交棒场景下**创建时即何斐**。
4. 建单 `fieldValueList` 可带计划开始 `79`**不要**在 create 同时写 `79+80`(同日会 400
5. 标签必须 PATCHcreate 带 tag 不落库);可与建子任务重叠;快轨交付/设计须与需求同标签。
6. `requests.Session` keep-alive**禁止**对共享 opener 加全局锁。
7. 脚本入口:`scripts/live_create_fast.py`v5快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂)。

View File

@@ -0,0 +1,660 @@
#!/usr/bin/env python3
"""YunxiaoPM 极速真实建单 v5快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂。"""
from __future__ import annotations
import json
import time
import urllib.parse
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any
try:
import browser_cookie3
except ImportError: # pragma: no cover
browser_cookie3 = None
import requests
ROOT = Path(__file__).resolve().parents[1]
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
STATUS = RUNTIME["status"]["req"]
TASK_STATUS = RUNTIME["status"]["task"]
FAST = RUNTIME.get("fields", {}).get("fast_track") or {}
SPACE = (
RUNTIME.get("project", {}).get("spaceIdentifier")
or (RUNTIME.get("project", {}).get("last_selected") or {}).get("spaceIdentifier")
)
if not SPACE:
raise RuntimeError(
"未选定项目 spaceIdentifier须先走门禁 PJ 点选,或设置 runtime project.last_selected"
)
REQ_TYPE = RUNTIME["workitem_types"]["product_req"]["identifier"]
TASK_TYPE = RUNTIME["workitem_types"]["task"]["identifier"]
HEFEI = RUNTIME["people"]["hefei"]["identifier"]
WANG = RUNTIME["people"].get("wangmian", {}).get("identifier", "6811df000601d2fea60144a9")
PRI = RUNTIME["priority"][""]
TAG_FAULT = RUNTIME.get("tags", {}).get("故障管理", "ceb526a7343995577645317e9a")
PLACEHOLDER = RUNTIME["delivery_placeholder"]
PROTO = "https://prototype.lnoneos.com/vehicle-fault-handling/index.html"
TZ = timezone(timedelta(hours=8))
TODAY = datetime.now(TZ).strftime("%Y-%m-%d")
NOON = f"{TODAY} 12:00:00"
EOD = f"{TODAY} 23:59:59"
NOON_MS = str(
int(datetime.now(TZ).replace(hour=12, minute=0, second=0, microsecond=0).timestamp() * 1000)
)
START_MS = str(
int(datetime.now(TZ).replace(hour=9, minute=0, second=0, microsecond=0).timestamp() * 1000)
)
END_MS = str(
int(datetime.now(TZ).replace(hour=11, minute=0, second=0, microsecond=0).timestamp() * 1000)
)
FAST_EST = int(FAST.get("req_estimated_hours", 2))
FAST_ACT = int(FAST.get("req_actual_hours", 2))
PENDING = STATUS["待处理"]
DESIGN_DONE = STATUS["设计完成"]
PENDING_DEV = STATUS["待开发"]
TASK_DONE = TASK_STATUS["已完成"]
_COOKIE = ""
_XSRF = ""
def load_auth() -> None:
global _COOKIE, _XSRF
jar: dict[str, str] = {}
if browser_cookie3:
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
try:
for c in browser_cookie3.chrome(domain_name=domain):
jar[c.name] = c.value
except Exception:
pass
if not jar:
p = Path("/tmp/yunxiao_cookies.json")
if p.exists():
raw = json.loads(p.read_text())
jar = (
raw
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
)
_COOKIE = "; ".join(f"{k}={v}" for k, v in jar.items())
x = jar.get("XSRF-TOKEN", "")
_XSRF = urllib.parse.unquote(x) if "%" in x else x
if not _XSRF:
raise RuntimeError("缺少 XSRF-TOKEN请先在 Chrome 登录 devops.aliyun.com")
def session() -> requests.Session:
s = requests.Session()
s.headers.update(
{
"Content-Type": "application/json",
"Cookie": _COOKIE,
"x-xsrf-token": _XSRF,
"X-XSRF-TOKEN": _XSRF,
"Origin": "https://devops.aliyun.com",
"Referer": f"https://devops.aliyun.com/projex/project/{SPACE}/req",
"accept": "application/json",
"User-Agent": "YunxiaoPM-live_create_fast/5.0",
"Connection": "keep-alive",
}
)
return s
def api(s: requests.Session, method: str, url: str, body: Any = None) -> dict:
r = s.request(method, url, json=body, timeout=60)
try:
return r.json()
except Exception:
r.raise_for_status()
raise
def create(s: requests.Session, payload: dict) -> dict:
url = "https://devops.aliyun.com/projex/api/workitem/workitem?_input_charset=utf-8"
j = api(s, "POST", url, payload)
r = j.get("result") or {}
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
return r
j = api(s, "PUT", url, payload)
r = j.get("result") or {}
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
return r
raise RuntimeError(f"create failed: {j}")
def get(s: requests.Session, wid: str) -> dict:
return api(
s,
"GET",
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
)["result"]
def apply_tag(s: requests.Session, wid: str, tag_id: str = TAG_FAULT) -> None:
j = api(
s,
"PATCH",
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
{
"workitemIdentifier": wid,
"propertyKey": "tag",
"propertyValue": tag_id,
"operateType": "COVER",
},
)
if j.get("code") != 200:
raise RuntimeError(f"tag failed {wid}: {j}")
def set_document(s: requests.Session, wid: str, html: str) -> None:
j = api(
s,
"PATCH",
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/document?_input_charset=utf-8",
{"content": html, "formatType": "RICHTEXT"},
)
if j.get("code") != 200 or j.get("errorMsg"):
raise RuntimeError(f"document failed {wid}: {j}")
def set_fields(s: requests.Session, wid: str, pairs: list[tuple[str, str]]) -> None:
data = urllib.parse.urlencode(
{
"fieldValueList": json.dumps(
[{"fieldIdentifier": k, "value": v} for k, v in pairs], ensure_ascii=False
)
}
)
r = s.post(
f"https://devops.aliyun.com/projex/api/workitem/workitem/field/value/{wid}?_input_charset=utf-8",
data=data,
headers={"Content-Type": "application/x-www-form-urlencoded"},
timeout=60,
)
j = r.json()
if j.get("code") != 200:
raise RuntimeError(f"field/value failed {wid}: {j}")
def set_estimate_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
est = api(
s,
"GET",
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/list?workitemIdentifier={wid}",
).get("result") or []
for row in est:
eid = row.get("identifier")
if eid:
api(
s,
"DELETE",
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/{wid}/{eid}",
)
j = api(
s,
"POST",
"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate?_input_charset=utf-8",
{
"workitemIdentifier": wid,
"spentTime": hours,
"type": "develop",
"description": "快轨默认预计工时",
"recordUserIdentifier": user,
"forCreate": False,
"containsRestDay": False,
},
)
if j.get("code") != 200:
raise RuntimeError(f"estimate failed {wid}: {j}")
def set_actual_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
j = api(
s,
"POST",
"https://devops.aliyun.com/projex/api/workitem/workitem/time?_input_charset=utf-8",
{
"workitemIdentifier": wid,
"actualTime": hours,
"type": "develop",
"description": "快轨默认实际工时",
"recordUserIdentifier": user,
"gmtStart": START_MS,
"gmtEnd": END_MS,
},
)
if j.get("code") != 200 or not j.get("result"):
raise RuntimeError(f"actual time failed {wid}: {j}")
def try_associate_to_req(s: requests.Session, stage_id: str, req_id: str) -> bool:
"""建后补 ASSOCIATED→需求。Cookie 下常失败,成功返回 True。"""
bodies = [
{"relationIdentifier": "ASSOCIATED", "toWorkitemIdentifier": req_id},
{
"relationIdentifier": "ASSOCIATED",
"fromWorkitemIdentifier": stage_id,
"toWorkitemIdentifier": req_id,
},
]
for body in bodies:
for url in (
f"https://devops.aliyun.com/projex/api/workitem/workitem/{stage_id}/relation/record?_input_charset=utf-8",
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{stage_id}/relation/record?_input_charset=utf-8",
):
j = api(s, "POST", url, body)
if j.get("code") == 200 and j.get("result") not in (None, False):
if not (isinstance(j.get("result"), dict) and j["result"].get("status") in (404, 405)):
rows = list_associated(s, stage_id)
if req_id in {r.get("identifier") for r in rows}:
return True
return False
def transit(s: requests.Session, wid: str, from_status: str, to_status: str) -> None:
if from_status == to_status:
return
j = api(
s,
"POST",
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/status/transit?_input_charset=utf-8",
{"fromStatus": from_status, "toStatus": to_status},
)
if not (j.get("code") == 200 and j.get("result") is True):
raise RuntimeError(f"transit {wid} {from_status}->{to_status}: {j}")
def md_to_html(md: str) -> str:
parts = []
for line in md.splitlines():
if line.startswith("## "):
parts.append(f"<h2>{line[3:]}</h2>")
elif line.startswith("### "):
parts.append(f"<h3>{line[4:]}</h3>")
elif line.startswith("- "):
parts.append(f"<p>• {line[2:]}</p>")
elif line.strip():
parts.append(f"<p>{line}</p>")
return "".join(parts)
def req_document_html(s: requests.Session, rid: str) -> str:
w = get(s, rid)
return ((w.get("document") or {}).get("content") or w.get("description") or "").strip()
def req_payload(subject: str, html: str) -> dict:
return {
"subject": subject,
"description": html,
"formatType": "RICHTEXT",
"document": {"content": html, "formatType": "RICHTEXT"},
"spaceIdentifier": SPACE,
"space": SPACE,
"spaceType": "Project",
"workitemTypeIdentifier": REQ_TYPE,
"workitemType": REQ_TYPE,
"categoryIdentifier": "Req",
"category": "Req",
"assignedTo": WANG,
"fieldValueList": [
{"fieldIdentifier": "priority", "value": PRI},
{"fieldIdentifier": "assignedTo", "value": WANG},
],
"attachmentIdList": [],
"cloneFrom": None,
"createWorkitemRelationList": [],
}
def task_payload(
subject: str,
html: str,
assignee: str,
*,
plan_start: bool = True,
associated_req: str | None = None,
parent_delivery: str | None = None,
) -> dict:
fvl = [
{"fieldIdentifier": "priority", "value": PRI},
{"fieldIdentifier": "assignedTo", "value": assignee},
]
if plan_start:
fvl.append({"fieldIdentifier": "79", "value": NOON_MS})
payload: dict[str, Any] = {
"subject": subject,
"description": html,
"formatType": "RICHTEXT",
"spaceIdentifier": SPACE,
"space": SPACE,
"spaceType": "Project",
"workitemTypeIdentifier": TASK_TYPE,
"workitemType": TASK_TYPE,
"categoryIdentifier": "Task",
"category": "Task",
"assignedTo": assignee,
"fieldValueList": fvl,
"attachmentIdList": [],
"cloneFrom": None,
}
if parent_delivery:
payload["parent"] = parent_delivery
payload["parentIdentifier"] = parent_delivery
payload["createWorkitemRelationInfo"] = {
"relatedWorkitemIdentifier": parent_delivery,
"relatedToRelationIdentifier": "TASK_SUB",
}
else:
if not associated_req:
raise ValueError("associated_req required for delivery: ASSOCIATED→需求")
payload["createWorkitemRelationInfo"] = {
"relatedWorkitemIdentifier": associated_req,
"relatedToRelationIdentifier": "ASSOCIATED",
}
return payload
def list_associated(s: requests.Session, wid: str) -> list[dict]:
j = api(
s,
"GET",
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{wid}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true",
)
return j.get("result") or []
def assert_associated_to_req(s: requests.Session, wid: str, req_id: str, label: str) -> None:
rows = list_associated(s, wid)
ids = {r.get("identifier") for r in rows}
if req_id not in ids:
raise RuntimeError(
f"{label} 关联项未挂需求:期望 {req_id},实际 {[r.get('serialNumber') for r in rows]}"
)
AUTO_RDO = """## 原始诉求AutoRDO
运维需在故障处置页承接机器人上报的故障,完成处置、挂起与归档,并保留证据链;工作台相关统计口径需与处置页一致
待确认:
- 本期是否含真实短信/邮件通道(现口径一般为演示模板)
## 工作项编号(系统)
- 交付:待建
- 分析:待建
- 设计:待建
"""
def summarize_from_create(w: dict, *, status: str, assignee_name: str) -> dict:
return {
"serial": w.get("serialNumber"),
"id": w.get("identifier"),
"subject": w.get("subject"),
"status": status,
"assignee": assignee_name,
"parent": w.get("parentIdentifier"),
}
def build_normal() -> dict:
t0 = time.perf_counter()
s = session()
title = "【新增】故障处置YunxiaoPMapp标准·极速v2"
req = create(s, req_payload(title, md_to_html(AUTO_RDO + f"\n原型:{PROTO}\n")))
rid = req["identifier"]
with ThreadPoolExecutor(max_workers=2) as pool:
f_tag_r = pool.submit(apply_tag, session(), rid)
f_deliv = pool.submit(
create,
session(),
task_payload(
f"【交付】{title}",
f"<p>{PLACEHOLDER}</p>",
HEFEI,
associated_req=rid,
),
)
deliv = f_deliv.result()
f_tag_r.result()
did = deliv["identifier"]
with ThreadPoolExecutor(max_workers=3) as pool:
f_tag_d = pool.submit(apply_tag, session(), did)
f_ana = pool.submit(
create,
session(),
task_payload(
f"【分析】{title}",
"<p>分析阶段:故障处置台账、挂起归档与证据链。</p>",
WANG,
associated_req=rid,
parent_delivery=did,
),
)
f_des = pool.submit(
create,
session(),
task_payload(
f"【设计】{title}",
f"<p>设计阶段:对齐原型 {PROTO}</p>",
WANG,
associated_req=rid,
parent_delivery=did,
),
)
ana = f_ana.result()
des = f_des.result()
f_tag_d.result()
with ThreadPoolExecutor(max_workers=3) as pool:
list(
as_completed(
[
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
pool.submit(transit, session(), ana["identifier"], PENDING, TASK_DONE),
pool.submit(transit, session(), des["identifier"], PENDING, TASK_DONE),
]
)
)
transit(s, rid, DESIGN_DONE, PENDING_DEV)
return {
"path": "normal",
"elapsed_s": round(time.perf_counter() - t0, 3),
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
"analysis": summarize_from_create(ana, status="已完成", assignee_name="王冕"),
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
}
def build_fast(
*,
tag_id: str = TAG_FAULT,
has_prototype: bool = True,
delivery_html: str | None = None,
) -> dict:
"""无单快轨。
- 设计描述 = 需求 document
- 交付描述 = 手工同步需求正文(无原型)或传入 AutoPRD HTML禁止无故占位
- 设计 79/80=当日;交付 79=当日
- 需求/交付/设计同标签
- 需求预计/实际工时各 2
- 设计 TASK_SUB→交付后尝试 ASSOCIATED→需求
"""
t0 = time.perf_counter()
s = session()
title = "【新增】故障处置YunxiaoPM快轨·极速v5"
req_html = md_to_html(AUTO_RDO + (f"\n原型:{PROTO}\n" if has_prototype else "\n"))
req = create(s, req_payload(title, req_html))
rid = req["identifier"]
# 以落库 document 为准(与手动建需后读需求一致)
req_html = req_document_html(s, rid) or req_html
if delivery_html:
deliv_html = delivery_html
desc_source = "autoprd"
elif req_html.strip():
deliv_html = req_html
desc_source = "manual_sync"
else:
deliv_html = f"<p>{PLACEHOLDER}</p>"
desc_source = "placeholder"
with ThreadPoolExecutor(max_workers=2) as pool:
f_tag_r = pool.submit(apply_tag, session(), rid, tag_id)
f_deliv = pool.submit(
create,
session(),
task_payload(
f"【交付】{title}",
deliv_html,
HEFEI,
associated_req=rid,
),
)
deliv = f_deliv.result()
f_tag_r.result()
did = deliv["identifier"]
with ThreadPoolExecutor(max_workers=2) as pool:
f_tag_d = pool.submit(apply_tag, session(), did, tag_id)
f_des = pool.submit(
create,
session(),
task_payload(
f"【设计】{title}",
req_html,
WANG,
parent_delivery=did,
),
)
des = f_des.result()
f_tag_d.result()
des_id = des["identifier"]
apply_tag(s, des_id, tag_id)
# 计划时间设计起止当日交付开始当日create 已带 79再 field/value 加固)
set_fields(s, des_id, [("79", NOON), ("80", EOD)])
set_fields(s, did, [("79", NOON)])
# 设计关联项补挂需求(可能失败,回报 risk
design_assoc_ok = try_associate_to_req(s, des_id, rid)
with ThreadPoolExecutor(max_workers=2) as pool:
list(
as_completed(
[
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
pool.submit(transit, session(), des_id, PENDING, TASK_DONE),
]
)
)
transit(s, rid, DESIGN_DONE, PENDING_DEV)
set_estimate_hours(s, rid, FAST_EST)
set_actual_hours(s, rid, FAST_ACT)
risk = None
if desc_source == "placeholder":
risk = "交付描述仍为占位"
if not design_assoc_ok:
risk = (risk + "" if risk else "") + "设计 ASSOCIATED→需求补挂失败Cookie须 UI/OpenAPI 兜底"
return {
"path": "fast",
"elapsed_s": round(time.perf_counter() - t0, 3),
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
"analysis": None,
"delivery_desc_source": desc_source,
"design_associated_ok": design_assoc_ok,
"risk": risk,
}
def main() -> None:
auth0 = time.perf_counter()
load_auth()
auth_s = round(time.perf_counter() - auth0, 3)
wall0 = time.perf_counter()
with ThreadPoolExecutor(max_workers=2) as pool:
f_fast = pool.submit(build_fast)
f_normal = pool.submit(build_normal)
fast = f_fast.result()
normal = f_normal.result()
build_s = round(time.perf_counter() - wall0, 3)
s = session()
assert_associated_to_req(s, normal["delivery"]["id"], normal["req"]["id"], "normal.delivery")
assert_associated_to_req(s, fast["delivery"]["id"], fast["req"]["id"], "fast.delivery")
def assert_sub(delivery_id: str, child_id: str, label: str) -> None:
rows = api(
s,
"GET",
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{delivery_id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true",
).get("result") or []
ids = {r.get("identifier") for r in rows}
if child_id not in ids:
raise RuntimeError(
f"{label} 未出现在交付子项:期望 {child_id},实际 {[r.get('serialNumber') for r in rows]}"
)
assert_sub(normal["delivery"]["id"], normal["analysis"]["id"], "normal.analysis")
assert_sub(normal["delivery"]["id"], normal["design"]["id"], "normal.design")
assert_sub(fast["delivery"]["id"], fast["design"]["id"], "fast.design")
verify = {
"normal_req": get(s, normal["req"]["id"])["status"]["displayName"],
"fast_req": get(s, fast["req"]["id"])["status"]["displayName"],
"normal_delivery_assignee": (
get(s, normal["delivery"]["id"]).get("assignedTo") or {}
).get("displayName"),
"fast_delivery_assignee": (get(s, fast["delivery"]["id"]).get("assignedTo") or {}).get(
"displayName"
),
"delivery_associated_ok": True,
"stage_tasks_as_sub_ok": True,
"fast_design_associated_ok": fast.get("design_associated_ok"),
}
out = {
"normal": normal,
"fast": fast,
"verify": verify,
"auth_elapsed_s": auth_s,
"wall_elapsed_s": build_s,
"created_at": datetime.now(TZ).isoformat(),
"mode": "live_create_fast_v5_fast_track_rules",
"opts": {
"create_includes_plan_start": True,
"skip_plan_end_on_create": True,
"tracked_transit_no_get": True,
"delivery_assignee_hefei_at_create": True,
"overlap_tag_with_create": True,
"fast_req_hours": f"{FAST_EST}+{FAST_ACT}",
"relation": "delivery ASSOCIATED→req; analysis/design TASK_SUB→delivery; design post ASSOCIATED→req",
"http": "requests.Session keep-alive",
},
}
Path("/tmp/yunxiao_pmapp_fast_v2_result.json").write_text(
json.dumps(out, ensure_ascii=False, indent=2)
)
print(json.dumps(out, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,60 @@
# 交付树模型与关联约定
## 真相源
```text
需求状态 = 阶段看板唯一真相(分析中/设计中/待开发…)
【交付】任务 = 该需求的交付容器(每需求最多 1 条)
【分析】/【设计】 = YunxiaoPMapp 在交付下建的阶段子项
【开发】/【测试】 = 另属开发 Skill / 测试 Skill不进本包
ASSOCIATED = 横向挂钩(【交付】 ↔ 需求)
SUB / TASK_SUB = 纵向拆解(交付 → 分析/设计)
```
## 关系验收
| 关系 | 用在哪里 | 验收 | 优先级 |
|---|---|---|---|
| ASSOCIATED | **仅【交付】** ↔ 需求 | 交付详情「关联项」能看到需求(**强制** | 交付必过 |
| TASK_SUB | 【分析】/【设计】 → 【交付】 | 交付详情「子项」能看到阶段任务(**强制** | 阶段任务必过 |
建单规则Cookie 路径 · 同一 create 只能一条 `createWorkitemRelationInfo`
| 对象 | `createWorkitemRelationInfo` | 另写字段 |
|---|---|---|
| 【交付】 | `ASSOCIATED` → 需求 | — |
| 【分析】/【设计】 | `TASK_SUB` → 交付 | `parent` + `parentIdentifier` = 交付 |
**禁止**对分析/设计只写 `parentIdentifier` + `ASSOCIATED→需求`关联项可能有但交付「子项」仍为空ONEOS-246/247 已复现)。
勿用 `PARENT` 冒充关联项。细则见 [live-api.md](live-api.md)。
## 禁止
| 禁止 | 说明 |
|---|---|
| 创建或描述【开发】/【测试】 | 口令与回报均不出现 |
| 分析/设计未挂成交付子项(无 TASK_SUB | 交付「子项」为 0交棒验收失败 |
| 用任务名称/标题做唯一性或查重 | 不得 `subject` 匹配复用 |
| 同一需求认定多个交付任务编号 | 列出编号请人合并后再继续 |
| 功能模块标签用「分析/设计/交付」 | 模块标签打在需求(可选交付)上 |
## 任务标题(仅展示)
- 【交付】+ 需求标题
- 【分析】+ 需求标题
- 【设计】+ 需求标题
标题可改,**不参与查重**。
## 任务编号唯一性
**唯一允许的查重/复用渠道:云效任务编号**(如 `ONEOS-99` / `serialNumber`)。
| 场景 | 正确 | 错误 |
|---|---|---|
| 首次创建【交付】 | 建单成功后回报并写入「工作项编号(系统)」 | 下次用标题搜 |
| 复用【交付】 | 口令或编号区块带 `交付任务=ONEOS-xx` | list 后按 subject 相等 |
| 判断是否已有交付 | 编号区块或交付 ASSOCIATED 编号集合 | 数【交付】开头标题 |
| 分析/设计幂等 | 仅已登记编号 | 按【分析】+需求标题 |
按编号命中则复用;**计划开始已有值禁止改写**。

View File

@@ -0,0 +1,49 @@
# 验收清单与回报
## apply 后必须自检
| # | 项 | 通过标准 |
|---|---|---|
| 1 | 需求编号 | 回报含 ONEOS-xx |
| 2 | 任务编号 | 交付/分析/设计凡新建或操作均回报编号;禁止只报标题 |
| 3 | 编号区块 | 需求「工作项编号(系统)」与实际一致 |
| 4 | ASSOCIATED | **仅交付**详情关联项可见需求(`createWorkitemRelationInfo=ASSOCIATED`;禁止 PARENT 冒充) |
| 5 | SUB | **必过**:分析/设计 create 用 `TASK_SUB→交付`(含 `parent`+`parentIdentifier`交付「子项」tab 须可见。与 ASSOCIATED 同 create 互斥,阶段任务关联项可空(见 live-api.md |
| 6 | 计划开始 | 未误覆盖已有值 |
| 7 | 阶段日历工时 | 有计划完成时已写入;脚注存在;回报用语正确 |
| 8 | 交棒 | 需求=待开发;交付负责人=何斐(交棒场景) |
| 9 | 占位风险 | 交付仍占位时首行标红 |
| 10 | 负向 | 本轮**无**【开发】/【测试】任务;未按标题查重 |
设计完成额外AutoPRD 段已写交付非占位除非失败停下ZIP+截图已挂或已列出缺项。
迭代额外:只挂【交付】(需求不挂);版本号符合递增规则。
## 回报模板(精简)
```text
【YunxiaoPM】
风险:(若有占位交棒则首行标红)
需求ONEOS-xx | 状态=…
交付ONEOS-a | 负责人=…
分析ONEOS-b | …(无则写无)
设计ONEOS-c | …(无则写无)
阶段日历工时:分析 Hh / 设计 Hh若本轮写入
附件:…(若本轮)
迭代:…(若本轮)
下一步:请技术经理使用开发 Skill交棒后
```
## 适合全自动 vs 人工门禁
| 适合全自动 | 建议半自动/人工门禁 |
|---|---|
| 建单、打标签、挂迭代、写描述、建交付树、改状态、交棒负责人、幂等查重 | **PJ 云效项目点选**、受理(已确认)、是否快轨、设计完成是否真可开发、跨需求优先级与迭代容量、回退与取消 |
## 实写性能2026-07-23 复盘)
| 项 | 要求 |
|---|---|
| 改状态 | 只用 `status/transit`(见 [live-api.md](live-api.md) |
| 改【交付】负责人 | 只用 `PATCH …/{id}` + `propertyKey=assignedTo` |
| 极速复测 | `scripts/live_create_fast.py`;默认不开浏览器 |

View File

@@ -0,0 +1,22 @@
# 口令面
```text
记录需求:…;项目=必选·Plan 点选);优先级=紧急|高|中|低;标签=…;提交部门=…;提交人=…;推进至=暂不推进|已确认|分析中|设计中|设计完成|待开发|待开发(快轨)
受理确认ONEOS-xx
开始分析ONEOS-xx → 【交付】+【分析】并回报编号
开始设计ONEOS-xx交付任务=…;分析任务=… → 【设计】+收口分析
设计完成ONEOS-xx设计任务=…;原型=…
交棒开发ONEOS-xx交付任务=… → 待开发 + 该编号负责人=何斐
快轨待开发ONEOS-xx → 待开发 +【交付】+【设计】(无【分析】)+ 交付负责人=何斐
编号直推:分析任务=ONEOS-b / 设计任务=ONEOS-c → 收口未完成计划完成 + 需求待开发 + 交付交棒何斐
创建迭代:版本类型=主|副|子;交付任务=ONEOS-a,ONEOS-b,…;名称前缀=…
AutoRDO粘贴聊天/附录音)→ 再记录需求
```
版本自动规则:取同前缀下最大 `Vx.y.z`(旧 `Vx.y` 视为 `Vx.y.0`)再按主/副/子递增;迭代名=`{前缀}{新版本}`
**PJ 项目**:新建需求/迭代前须点选云效项目(实时列表);禁止默认直指。见 [project-selection.md](project-selection.md)。
后续推进口令**优先显式带任务编号**;未带则读「工作项编号(系统)」;仍无则询问;**禁止按标题补全**。
YunxiaoPM 回报止于交棒;可一句「请技术经理使用开发 Skill」。

View File

@@ -0,0 +1,95 @@
# 压缩点选(`1a2b3a4d`
记录需求 Plan **默认**用编号题 + 字母选项;用户可用一行压缩答复确认。
## Plan 展示模板
```text
请回复压缩点选1a2b3a4d
(数字=题号,字母=选项;大小写不敏感;可写 1A2B3A4D
1. 类型
A. 新增
B. 优化
2. 项目(云效实时列表;建议项可标★)
A. 01_ONEOSONEOS
B. 02_小羚羚APPXLLAPP
C. …
3. 优先级
A. 紧急
B. 高
C. 中
D. 低
4. 标签(云效候选;建议项可标★)
A. 故障管理★
B. 还车应结款
C. …
```
可选续题(口令已齐则可写入清单、压缩串可不含):
```text
5. 推进至 …
6. 迭代 …
```
## 解析规则
| 规则 | 说明 |
|---|---|
| 形态 | `(题号)(字母)` 连续拼接,如 `1a2b3a4d` |
| 题号 | `1`=类型 `2`=项目 `3`=优先级 `4`=标签;可扩展 `5` `6` |
| 字母 | `a`→第 1 项 … `z`→第 26 项;超出选项数 → 非法,停 |
| 缺题 | 该题若口令已唯一预填且列表唯一命中,可用预填;否则停并追问缺题 |
| 多答同题 | 后写覆盖先写 |
| 非法字符 | 停,重贴模板 |
解析成功后 Plan 回显人话确认一行,例如:
```text
已解析 1a2b3a4d → 类型=新增;项目=02_小羚羚APP优先级=紧急;标签=D 项名)
确认后回复「执行」
```
用户再回「执行」才 apply仍守 Plan 门禁)。
## 与口令预填
口令已写 `类型新增项目01_ONEOS优先级标签故障管理` 时:
- 对应选项标 ★,并给出**建议压缩串**(如 `1a2a3b4a`),用户可直接改字母或整段重答。
- **不得**因有预填而跳过展示字母表;压缩确认(或逐题点选)仍是门禁。
## 标签未命中 → 自动重拉一次候选并重生选项
「标签无法对应」:口令标签名在**当前标签候选**中 0 命中(或多命中无法唯一)。
| 步骤 | 动作 |
|---|---|
| 1 | **自动重拉一次**标签候选(见下「标签候选来源」;强制刷新,不用旧缓存) |
| 2 | 用新列表**重新生成 4.A/B/C…** 选择项 |
| 3 | 回报:`已自动重拉标签列表(因无法对应)`;请用户重答 `4x` 或整串 |
| 4 | 仍无法对应 → 停;**禁止**第 3 次空转;**禁止**猜 tagId |
> 说明:此处重拉的是**标签候选列表**,不是项目列表。项目无法对应仍走 [project-selection.md](project-selection.md) 的「自动重拉一次」。
### 标签候选来源(当前已验证路径)
1. `runtime-ids.json``tags`
2. 目标项目(或预填项目)下近期工作项 `tag` 字段聚合去重
3. 重拉 = 再请求工作项列表聚合 + 合并 runtime命中后可回写 `tags` 缓存
(专用 `tag/list` Cookie API 尚未稳定;有稳定端点后改写入 `live-api.md` 并切换。)
## 项目列表顺序
生成 2. 选项时:口令预填/建议项目置 **A** 并标 ★,其余按云效返回顺序接 B/C/…。
## Agent 义务
1. 记录需求进 Plan 时必须输出本模板(至少 14 题)。
2. 收到压缩串先解析回显,再等「执行」。
3. 标签/项目无法对应:各自动重拉**一次**并刷新对应题选项。

View File

@@ -0,0 +1,69 @@
# 需求描述 vs 交付描述
两类描述职责不同;禁止混写;禁止建【交付】时把 AutoPRD 六大块提前塞进交付描述。
## A. 需求描述 · AutoRDO 清洗
| 项 | 规则 |
|---|---|
| 触发 | 对话建需求 / 碎片材料入库 |
| 调用 | **必须**使用独立 Skill「**`$AutoRDO`**」(`AutoRDO/SKILL.md`;本 Skill 不内嵌清洗细则) |
| 输入 | 聊天记录、录音、口述材料 |
| 处理 | 保留原意;书面化;去口头禅;**去除结尾句号**(细则在 AutoRDO `references/rules.md` |
| 输出 | 写入 `## 原始诉求AutoRDO` |
| 不做 | 本阶段不写 AutoPRD 六大块;不要求已有原型;不覆盖已有「产品说明」 |
口令:`AutoRDO…` → 确认后 `记录需求:【新增】标题;描述=整理稿;推进至=…`
## B. 交付描述
### B1. 标准路径(分析中起建交付)
| 时机 | 【交付】描述 |
|---|---|
| 首次创建起至设计完成前 | 固定文案:`等待设计任务完成后自动填入` |
| 设计完成时 | 用 AutoPRD「产品说明」正文替换占位 |
### B2. 无单快轨建交付(覆盖 B1
| 口令/材料 | 【交付】描述 |
|---|---|
| 手工描述(无指定原型) | **同步需求**当前手工/AutoRDO 正文;禁止占位 |
| 指定原型页面 | `$oneos-autoprd` 从原型生成写入;禁止占位 |
| 既无正文又无原型 | 才允许占位并标红风险 |
快轨【设计】描述始终复制需求当前描述正文(见 [fast-track.md](fast-track.md))。
## C. 需求描述双段模板(不可互相覆盖)
```markdown
## 原始诉求AutoRDO
(清洗稿;设计完成也不删除)
## 产品说明AutoPRD
(六大块+对象存储链接;未设计完成前可无此节或写「待设计完成后填入」)
## 工作项编号(系统)
- 交付:…
- 分析:…
- 设计:…
```
## D. 设计完成 · AutoPRD + 附件
前提:设计任务完成且已关联对应原型页。
1. 调用 **`$oneos-autoprd`AutoPRD**,产出并落盘 `.spec/requirements-prd.md` + 标注同步:
- 对象存储预览链接:`{baseUrl}/{prototype-id}/index.html`(禁止加 `prototypes/` 前缀、禁止去掉 `index.html`
- 产品说明 Markdown总览/角色/流程/状态/风险/交付等,见 AutoPRD 模板)
2. 写入需求 `## 产品说明AutoPRD`**禁止覆盖** `## 原始诉求AutoRDO` / `## 工作项编号(系统)`
3. 【交付】描述:按**交付任务编号**用产品说明正文**替换**占位(细则见 AutoPRD `references/yunxiao-delivery-sync.md`);可附「原始诉求见需求描述」。**创建【交付】时不得提前灌 MD。**
4. 附件(需求 +【交付】均挂;失败则不得声称成功):
- Make「导出 HTML含源码」ZIP → [make-export-attach.md](make-export-attach.md)
- Make「复制截图」全交互页 → 同上
缺原型 / AutoPRD 失败 / 导出或截图失败 → **不得**报到设计完成并宣称附件齐全;停下并列出缺项。
执行顺序:先 AutoPRD 落盘与附件就绪 → 再改需求/交付描述与设计计划完成 → 最后改需求状态。
**禁止**加载 `yunxiao-requirement-lifecycle`;阶段任务树只由本 SkillYunxiaoPMapp创建。

View File

@@ -0,0 +1,47 @@
# 无单快轨到待开发
适用:口令明确「快轨」或「推进至待开发」且当前需求尚无标准分析路径任务(或用户确认跳过分析)。
## 动作表
| 对象 | 动作 |
|---|---|
| 需求 | 状态 → **待开发****预计工时=2**、**实际工时=2**(覆盖同日 8h 日历工时默认);标签按口令;更新编号区块 |
| 【交付】 | 无则新建ASSOCIATED→需求勿用 PARENT负责人→何斐**计划开始=创建当日**`79`**不写**计划完成;**描述双路径**(见下);**标签与需求相同**;更新编号区块 |
| 【设计】 | **必须新建****TASK_SUB→交付**(交付「子项」须可见);**描述=复制需求当前描述正文**;计划开始/完成均=当日create 后 `field/value``79`+`80`);任务→完成态;**标签与需求相同**;建后再尝试 **ASSOCIATED→原始需求**Cookie 常失败,见 live-api失败须标红**子项优先于关联项**);更新编号区块 |
| 【分析】 | **禁止创建** |
## 交付描述双路径A1
| 口令/材料 | 【交付】描述 |
|---|---|
| **手工描述**(无指定原型) | 同步需求当前手工/AutoRDO 正文(与设计一致可复制 document |
| **指定原型页面** | 调用 `$oneos-autoprd`,从原型生成 AutoPRD「产品说明」写入【交付】 |
| 既无手工可同步正文、又无原型 | 才允许占位 `等待设计任务完成后自动填入`Plan 勾选交棒占位风险,回报首行标红 |
有手工或原型时**禁止**交棒占位。
## AutoPRD
- 快轨默认可不跑 AutoPRD**例外**:口令指定原型 → 交付走 AutoPRD 路径(上表)。
- 口令同时「设计完成 + 原型」时仍按步骤 4 灌需求产品说明段。
## 查重
只认任务编号。已有分析单不得因「快轨」被删除。
## 回报必含
- 需求 / 交付 / 设计编号
- 「快轨:未建分析;设计已同步需求描述并当日收口」
- 交付描述来源:手工同步 / AutoPRD / 占位(若占位则首行标红)
- 需求预计工时=2、实际工时=2
- 设计关联项含需求编号;交付子项含设计编号
## 与标准 / 编号直推对比
```text
标准:分析中→交付+分析 → 设计中→设计+收口分析 → 设计完成→收口设计 → 待开发交棒
快轨(无既有阶段单):→ 待开发:新建交付+设计+交棒何斐(无分析;设计当日收口;需求工时 2+2
编号直推:已有分析/设计编号 → 收口空计划完成 → 待开发+交付交棒(不新建冗余单)
```

View File

@@ -0,0 +1,20 @@
# 交棒门禁与回退最小集
## 交棒门禁(待开发)
| 情形 | 规则 |
|---|---|
| 【交付】描述已是 AutoPRD 正式说明(非占位) | 允许交棒Plan 正常列交付任务编号 + 负责人→何斐 |
| 【交付】描述仍为 `等待设计任务完成后自动填入` | **仍允许交棒**,但 Plan **必须**勾选风险项「交付描述仍为占位,技术侧仅可凭需求 AutoRDO 稿理解」;回报**首行标红**该风险;**禁止**静默交棒假装材料齐全 |
| 口令同时带原型且要求设计完成 | 先走步骤 4AutoPRD+附件)成功,再交棒,不再勾占位风险 |
## 回退 / 变更(最小集 · 兼容计划开始不篡改)
| 场景 | 规则 |
|---|---|
| 待开发 → 退回设计中 | 需求状态回退;【交付】负责人可改回创建人/产品;**交付计划开始不改**;若需重做设计 → **新开**设计任务编号(旧设计保持已收口,不改其计划开始);更新「工作项编号(系统)」中的设计编号为新号 |
| 设计完成后需求大变 | 不自动改状态Plan 询问是否回退设计中并新开设计编号;更新 AutoPRD 段AutoRDO 段保留并追加「变更纪要」 |
| 取消需求 | 关联任务标取消/废止;不删编号区块;不改已写计划开始 |
| 度量含义 | 交付计划开始保留 = 全周期仍从首次开工起算;回退重做会拉长日历工时——回报注明「含回退重做」 |
凡写云效的回退仍须走 Plan 门禁。

View File

@@ -0,0 +1,14 @@
# 交接契约(开发 Skill 入口)
YunxiaoPMapp 与开发 Skill **不要**互相 include 全文;仅认下列契约。
```text
PM 完成交棒 → 需求=待开发;【交付】任务编号=ONEOS-xx负责人=何斐ASSOCIATED 需求
若交付描述仍为占位 → 回报已标红风险
开发 Skill 入口 → 认「需求编号 + 交付任务编号」
占位时只可信需求「原始诉求AutoRDO」并有权要求产品补设计完成
```
共享常量(项目 ID、何斐 ID、节假日日历可引用本 Skill 的 `assets/` 短路径,勿加载整份对方规则。
测试 Skill 另开;本契约不覆盖提测/缺陷。

View File

@@ -0,0 +1,242 @@
# 云效实写 APIYunxiaoPMapp 已验证)
`verified_at`: 2026-07-25 · **项目须门禁 PJ 点选**(见 [project-selection.md](project-selection.md));历史验证样本项目为 `01_ONEOS` / 原「统一运营管理平台」(`last_selected.spaceIdentifier``assets/runtime-ids.json`,禁止未点选即使用)。
本文件只记**已跑通**的写法;禁止再盲试 `updateStatus` / 错误 `updateFieldValue` POST。
## 认证
- CookieChrome 域 `.aliyun.com` / `devops.aliyun.com``browser_cookie3` 或 Playwright storage
- Header`x-xsrf-token` = cookie `XSRF-TOKEN`URL 解码后)
- `Origin` / `Referer``https://devops.aliyun.com`
## 建单
`POST|PUT /projex/api/workitem/workitem?_input_charset=utf-8`
创建响应 `result.identifier` / `serialNumber` 即编号真相;**禁止按标题查重**。
## 改负责人(已通)
```http
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
{"propertyKey":"assignedTo","propertyValue":"<userId>","operateType":"COVER"}
```
交棒:【交付】`propertyValue` = 何斐 ID。
## 打标签(已通)
```http
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
{"workitemIdentifier":"{id}","propertyKey":"tag","propertyValue":"<tagId>[,<tagId>]","operateType":"COVER"}
```
## 改状态(已通 · 唯一推荐)
```http
POST /projex/api/workitem/workitem/{id}/status/transit?_input_charset=utf-8
{"fromStatus":"<status.identifier>","toStatus":"<status.identifier>"}
```
成功:`code=200``result=true`。失败时 `errorMsg` 含「不能流转」。
### 需求状态 ID本项目
| 显示名 | identifier |
|---|---|
| 待处理 | `100005` |
| 已确认 | `32` |
| 分析中 | `154395` |
| 设计中 | `156603` |
| 设计完成 | `307012` |
| 待开发 | `1582fc929d429111b925309493` |
### 任务状态 ID
| 显示名 | identifier |
|---|---|
| 待处理 | `100005` |
| 已完成 | `100014` |
### 极速交棒跳转(工作流允许)
从「待处理」菜单可见直达「设计完成」;推荐最少跳:
```text
待处理 → 设计完成 → 待开发
```
标准路径若需看板留痕,可走完整链:已确认→分析中→设计中→设计完成→待开发(仍用本 API勿开 UI
### 禁止(已证伪)
| 写法 | 结果 |
|---|---|
| `PATCH …/updateStatus` + `statusIdentifier` | `400 不能为空` |
| `PATCH …/{id}` + `propertyKey=status` | `property not found` |
| Playwright 点左侧/列表上的状态色块(`x<1100` | 假成功、状态不落库 |
仅当 `status/transit` 不可用时,才用 UI右侧详情状态钮`getBoundingClientRect().x > 1100`+ `.next-menu-item`
## 计划开始/完成 · 提交部门/人 · 预计工时2026-07-27 修订)
**通用字段写入(已通):**
```http
POST /projex/api/workitem/workitem/field/value/{workitemId}?_input_charset=utf-8
Content-Type: application/x-www-form-urlencoded
fieldValueList=[{"fieldIdentifier":"79","value":"2026-07-27 12:00:00"},{"fieldIdentifier":"3132597a9718d1c282b7ba5a0c","value":""},{"fieldIdentifier":"9e01269e96f91fbb97d36bf5b3","value":""}]
```
| 字段 | fieldIdentifier | value |
|---|---|---|
| 计划开始 | `79` | `YYYY-MM-DD HH:mm:ss`(推荐正午)或 epoch ms 字符串 |
| 计划完成 | `80` | 同上 |
| 提交部门 | `3132597a9718d1c282b7ba5a0c` | 纯文本 |
| 提交人 | `9e01269e96f91fbb97d36bf5b3` | 纯文本 |
**预计工时 `101586`:禁止直接改字段**(报「不可直接修改」)。须登记:
```http
POST /projex/api/workitem/workitem/time/estimate?_input_charset=utf-8
{"workitemIdentifier":"<id>","spentTime":8,"type":"develop","description":"","recordUserIdentifier":"<userId>","forCreate":false,"containsRestDay":false}
```
删除多余预估:`DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}`
列表:`GET …/time/estimate/list?workitemIdentifier=`
旧写法 `PATCH …/updateWorkitemFieldValue` 对上述自定义字段常 `400 不能为空`,勿再优先使用。
## 父子 / 子项 / 关联项(已通 · 2026-07-23 修订 · 子项优先)
### 关联项(【交付】强制 · ASSOCIATED
任务详情「关联项」只认 `ASSOCIATED`。**仅【交付】**建单时 `createWorkitemRelationInfo` 必须指向**需求**
```json
{
"createWorkitemRelationInfo": {
"relatedWorkitemIdentifier": "<需求id>",
"relatedToRelationIdentifier": "ASSOCIATED"
}
}
```
校验:
```http
GET /projex/api/workitem/v2/workitem/{id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
```
`result` 含该需求即通过。
### 禁止(关联项)
| 写法 | 结果 |
|---|---|
| `relatedToRelationIdentifier=PARENT` 把交付挂需求 | 详情可能有 parent**关联项仍为空** |
| 分析/设计只用 `ASSOCIATED→需求` + `parentIdentifier` | 关联项可能有,**交付子项仍为空**ONEOS-246/247 |
| 建后再 `POST …/relation/record` 补关系 | Cookie 路径下常报「不能关联相同的工作项」 |
| `createWorkitemRelationList` | 不落 ASSOCIATED |
### 子项(【分析】/【设计】强制 · TASK_SUB
「子项」页读 `PARENT_SUB` / `TASK_SUB`,分析/设计**必须**
```json
{
"parent": "<交付id>",
"parentIdentifier": "<交付id>",
"createWorkitemRelationInfo": {
"relatedWorkitemIdentifier": "<交付id>",
"relatedToRelationIdentifier": "TASK_SUB"
}
}
```
同一 create 只能带一条 `createWorkitemRelationInfo`
`ASSOCIATED→需求``TASK_SUB→交付` **不能同时写**
**产品优先级交付「子项」tab > 阶段任务「关联项」。**
交付本身仍必须 `ASSOCIATED→需求`。标准路径下分析/设计的「关联项」允许为空。
**无单快轨例外(设计双挂):** create 用 `TASK_SUB→交付` 后,须再补 **ASSOCIATED→原始需求**,使设计详情「关联项」可见需求。
```http
POST /projex/api/workitem/workitem/{id}/relation/record?_input_charset=utf-8
{"relationIdentifier":"ASSOCIATED","toWorkitemIdentifier":"<id>"}
```
**已证伪Cookie · 2026-07-27** 凡工作项**已创建**后再 `relation/record` 补挂(含 ASSOCIATED / TASK_SUB常报「不能关联相同的工作项」与是否已有父项无关。`createWorkitemRelationList` 亦不落 ASSOCIATED。
**可行路径:**
| 目标 | 做法 |
|---|---|
| 交付「子项」可见设计(优先) | create 带 `TASK_SUB→交付` |
| 设计「关联项」可见需求 | create 带 `ASSOCIATED→需求`(与上互斥,同 create 只能一条) |
| 双挂 | 需个人 `x-yunxiao-token` OpenAPICookie 路径**不得**声称成功 |
产品默认:**子项优先**;关联项失败须在回报中标红并列出缺项。
校验子项:
```http
GET /projex/api/workitem/v2/workitem/{id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true
```
结果须含对应分析/设计 identifier。
校验设计关联项:
```http
GET /projex/api/workitem/v2/workitem/{id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
```
`result` 须含原始需求 identifier。
### 无单快轨字段默认2026-07-27
| 对象 | 规则 |
|---|---|
| 【设计】描述 | 复制需求 document HTML |
| 【设计】`79`/`80` | 当日 `12:00:00` / `23:59:59`create 后 `field/value`(勿 create 同时带 79+80 |
| 【交付】描述 | 手工同步需求正文或原型→AutoPRD禁止无故占位 |
| 【交付】`79` | 创建当日;不写 `80` |
| 【交付】/【设计】标签 | 与需求相同,`PATCH propertyKey=tag` |
| 需求预计工时 | `time/estimate` **spentTime=2**(先删多余预估) |
| 需求实际工时 | `POST …/workitem/time`body 用 **`actualTime`**(非 spentTime+ `gmtStart`/`gmtEnd` epoch ms 字符串;见 `runtime-ids.json` `fields.actual_hours` |
| 描述更新 | `PATCH …/workitem/{id}/document``{"content":"<html>","formatType":"RICHTEXT"}` |
## 迭代挂接(已通 · 2026-07-27 · 只挂交付)
创建迭代:`POST /projex/api/workspace/sprint`(必填 `staffIds`;可写 `capacityHours`)。
挂【交付】到迭代:
```http
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
{"workitemIdentifier":"{id}","propertyKey":"sprint","propertyValue":"{sprintId}","operateType":"COVER"}
```
清空误挂(如需求):`propertyValue:""` + `operateType:"COVER"`
**校验**必须读 `/extra`(详情主接口常不含 sprint 字段,禁止据此判失败):
```http
GET /projex/api/workitem/workitem/{id}/extra?_input_charset=utf-8
result.sprint[].identifier / name
```
产品规则:**只挂【交付】**;需求 / 分析 / 设计默认不挂(除非口令显式)。
### 极速建单注意
1. Cookie 只刷一次;全程纯 HTTP默认**不开浏览器**。
2. 交付建完后,【分析】与【设计】**并行**创建(均 TASK_SUB→交付标准/快轨两树可并行。
3. 状态用 `transit` + **本地追踪 fromStatus**(禁止每次 GET负责人在交棒场景下**创建时即何斐**。
4. 建单 `fieldValueList` 可带计划开始 `79`**不要**在 create 同时写 `79+80`(同日会 400
5. 标签必须 PATCHcreate 带 tag 不落库);可与建子任务重叠;快轨交付/设计须与需求同标签。
6. `requests.Session` keep-alive**禁止**对共享 opener 加全局锁。
7. 脚本入口:`scripts/live_create_fast.py`v5快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂)。

View File

@@ -0,0 +1,59 @@
# 2026-07-23 真实建单复盘与极速优化
## 测试结论
标准 + 快轨均可建到「待开发」交棒;交付树、标签「故障管理」、快轨无【分析】均正确。
| 轮次 | 编号 |
|---|---|
| 第一轮(探测+UI | ONEOS-141147 |
| 极速 v1 | ONEOS-148154 |
| 极速 v2 | ONEOS-164177含中间探针 |
## 过程问题(已修)
| # | 问题 | 根因 | 修复 |
|---|---|---|---|
| 1 | 状态改不动 / 假成功 | 误用 `updateStatus`UI 点列表区 | `POST …/status/transit` |
| 2 | 负责人改不成 | `updateFieldValue` 错 | `PATCH …/{id}` + `assignedTo` |
| 3 | 状态 ID 不全 | 未抓网络 | 写入 `runtime-ids.json` |
| 4 | 极慢 | Playwright + 串行探测 | 纯 HTTP + 并行 |
| 5 | v1 仍偏慢 | 多余 GET、串行 PATCH 计划、交棒再改负责人 | 见下节 v2 |
## 性能对比
| 口径 | 优化前(第一轮) | 极速 v1 | 极速 v2本轮 |
|---|---|---|---|
| 会话墙钟 | ≈ **17.9 分钟** | — | — |
| 两路径并行建单墙钟 | ≈4.1 分钟自动化 | **4.4 s** | **2.2 s** |
| 标准单路径 | 失败反复 | 3.7 s | **2.2 s** |
| 快轨单路径 | 失败反复 | 3.7 s | **2.1 s** |
| 浏览器 | 多次 | 无 | 无 |
相对第一轮会话 ≈ **490×**;相对 v1 再快约 **2×**
## v2 压榨点(已落地)
1. `status/transit` **本地追踪** `fromStatus`,跳过每次 GET。
2. 建单 `fieldValueList` 带**计划开始(79)**;计划完成不在 create 写(同日会 400
3. 【交付】创建时负责人直接 **何斐**(省 PATCH
4. `requests.Session` keep-alive**去掉全局锁**(否则并行失效)。
5. 打标签与建子任务 **重叠**;两路径并行。
6. 交棒后汇总用创建响应,校验 GET 移出主路径计时。
## 探针结论(未采用)
| 尝试 | 结果 |
|---|---|
| create `fieldValueList` 带 tag | 建单成功但标签不落库 → 仍须 PATCH |
| create 同时写 79+80 | `400 计划…转化异常` |
| urllib 全局 lock + 单 opener | 并行被串行化,单路径 ≈4 s |
## 仍可再压(收益变小)
1. 标签 API 若将来支持 create 落库,可再少 24 次 PATCH。
2. HTTP/2 或连接预热DNS/TLS 复用到进程级)。
3. 业务允许「建单即待开发」且平台支持初始状态 → 少 2 次 transit。
4. 计划完成改为交棒后异步补写(当前故意跳过)。
脚本:`scripts/live_create_fast.py`mode=`live_create_fast_v2`)。

View File

@@ -0,0 +1,53 @@
# Make 导出与截图附件
设计完成(步骤 4且已关联原型页时需求与【交付】均挂附件。任一侧失败 → 不得声称设计完成附件齐全。
## 1. 导出 HTML含源码ZIP
与 Make「发布 → 导出 HTML含源码」对齐。
优先本地 Make Admin
```http
GET {adminOrigin}/api/export-html?path={prototypePath}&projectId={projectId}&includeSource=true
```
| 参数 | 要求 |
|---|---|
| `path` | 原型路径(如 `prototypes/oneos-h5-vehicle-assets` |
| `includeSource` | **必须** `true` |
| 响应 | ZIP`PK` 头);文件名建议 `{prototype-id}-html-source.zip` |
失败时:提示用户在 Make 客户端对该原型执行「发布 → 导出 HTML含源码把 ZIP 路径发回。
**禁止**用「仅对象存储链接」冒充已附带源码包。
## 2. 复制截图(全交互页)
1. Make「发布 → **复制截图**」(或等价:导出该原型主界面及所有交互页截图)。
2. 上传到需求附件与【交付】附件。
3. 缺页/失败 → 列出缺项,不得报成功。
## 3. 挂载范围
同一 ZIP / 同一批截图:
1. 上传到需求 identifier
2. 上传到【交付】任务 identifier
优先 API未知 upload 端点时用已登录浏览器在详情页「附件」上传。
## 4. 与对象存储的关系
| 产物 | 用途 |
|---|---|
| `{baseUrl}/{id}/index.html` | AutoPRD 描述内可点预览链接 |
| 导出 ZIP含源码 | 附件,供开发离线打开 |
| 交互页截图 | 附件,供评审/开发对照 |
三者职责不同,不可互相替代。
## 负向
- 不得导出错误原型页(须 Plan 确认原型路径/名称)。
- 不得把别的需求的旧 ZIP 复用到新需求。
- 快轨交棒默认不跑本附件流程(除非口令同时设计完成+原型)。

View File

@@ -0,0 +1,60 @@
# 交付树模型与关联约定
## 真相源
```text
需求状态 = 阶段看板唯一真相(分析中/设计中/待开发…)
【交付】任务 = 该需求的交付容器(每需求最多 1 条)
【分析】/【设计】 = YunxiaoPMapp 在交付下建的阶段子项
【开发】/【测试】 = 另属开发 Skill / 测试 Skill不进本包
ASSOCIATED = 横向挂钩(【交付】 ↔ 需求)
SUB / TASK_SUB = 纵向拆解(交付 → 分析/设计)
```
## 关系验收
| 关系 | 用在哪里 | 验收 | 优先级 |
|---|---|---|---|
| ASSOCIATED | **仅【交付】** ↔ 需求 | 交付详情「关联项」能看到需求(**强制** | 交付必过 |
| TASK_SUB | 【分析】/【设计】 → 【交付】 | 交付详情「子项」能看到阶段任务(**强制** | 阶段任务必过 |
建单规则Cookie 路径 · 同一 create 只能一条 `createWorkitemRelationInfo`
| 对象 | `createWorkitemRelationInfo` | 另写字段 |
|---|---|---|
| 【交付】 | `ASSOCIATED` → 需求 | — |
| 【分析】/【设计】 | `TASK_SUB` → 交付 | `parent` + `parentIdentifier` = 交付 |
**禁止**对分析/设计只写 `parentIdentifier` + `ASSOCIATED→需求`关联项可能有但交付「子项」仍为空ONEOS-246/247 已复现)。
勿用 `PARENT` 冒充关联项。细则见 [live-api.md](live-api.md)。
## 禁止
| 禁止 | 说明 |
|---|---|
| 创建或描述【开发】/【测试】 | 口令与回报均不出现 |
| 分析/设计未挂成交付子项(无 TASK_SUB | 交付「子项」为 0交棒验收失败 |
| 用任务名称/标题做唯一性或查重 | 不得 `subject` 匹配复用 |
| 同一需求认定多个交付任务编号 | 列出编号请人合并后再继续 |
| 功能模块标签用「分析/设计/交付」 | 模块标签打在需求(可选交付)上 |
## 任务标题(仅展示)
- 【交付】+ 需求标题
- 【分析】+ 需求标题
- 【设计】+ 需求标题
标题可改,**不参与查重**。
## 任务编号唯一性
**唯一允许的查重/复用渠道:云效任务编号**(如 `ONEOS-99` / `serialNumber`)。
| 场景 | 正确 | 错误 |
|---|---|---|
| 首次创建【交付】 | 建单成功后回报并写入「工作项编号(系统)」 | 下次用标题搜 |
| 复用【交付】 | 口令或编号区块带 `交付任务=ONEOS-xx` | list 后按 subject 相等 |
| 判断是否已有交付 | 编号区块或交付 ASSOCIATED 编号集合 | 数【交付】开头标题 |
| 分析/设计幂等 | 仅已登记编号 | 按【分析】+需求标题 |
按编号命中则复用;**计划开始已有值禁止改写**。

View File

@@ -0,0 +1,35 @@
# 编号直推到待开发
适用:标准路径已建过【分析】和/或【设计】,用**任务编号**一口气推到待开发交棒。
## 入口(只认编号)
```text
交棒开发:需求=ONEOS-xx交付任务=ONEOS-a分析任务=ONEOS-b设计任务=ONEOS-c
交棒开发:分析任务=ONEOS-b → 由分析 ASSOCIATED/SUB 反查需求与交付
交棒开发:设计任务=ONEOS-c → 同上反查
```
禁止用标题猜。编号对不上关联树 → 停下列出关联,不瞎改。
## 动作表
| 对象 | 动作 |
|---|---|
| 需求 | 状态 → **待开发**(按云效连跳) |
| 【交付】 | **必须**用交付任务编号定位;负责人→何斐;不改计划开始;不写计划完成;描述仍占位则保持(除非同时设计完成+原型+AutoPRD |
| 【分析】 | 若有编号:计划完成若为空 → 写当日并推工时;**不新建**第二条 |
| 【设计】 | 若有编号:计划完成若为空 → 写当日并推工时;**不新建**第二条 |
| 仅有分析、尚无设计 | **不强制补建【设计】**(与无单快轨区分);回报注明「无设计任务编号」 |
| 仅有设计、无分析 | 收口设计 + 交棒;**不补建分析** |
## 与无单快轨区别
| | 无单快轨 | 编号直推 |
|---|---|---|
| 前提 | 尚无分析/设计阶段单(或明确跳过分析) | 已有分析和/或设计**任务编号** |
| 【分析】 | 禁止创建 | 有编号则收口,无则不建 |
| 【设计】 | 必须新建且当日收口 | 有编号则收口;仅分析无设计时不强制新建 |
| 定位 | 新建后登记编号 | **仅任务编号**定位/反查 |
仍不创建【开发】/【测试】。交棒占位风险见 [handoff-and-rollback.md](handoff-and-rollback.md)。

View File

@@ -0,0 +1,73 @@
# 门禁 PJ · 云效项目选择(强制点选)
**新建需求 / 新建任务树 / 创建迭代 / 其它写入依赖 `spaceIdentifier`** 的操作,项目必须由用户从云效实时列表**点选**。禁止静默使用 `runtime-ids.json` 里的默认 `project.spaceIdentifier`
## 何时触发
| 场景 | 是否必须选项目 |
|---|---|
| 记录需求 / 无单快轨新建 | **必须** |
| 创建迭代(新挂项目空间) | **必须**(与需求同项目时沿用已锁定项,仍须在 Plan 写出项目名+ID |
| 仅推进已有编号(受理确认、开始分析…) | **不必重选**以该编号所在项目为准Plan 写出项目名 |
| 只读查询 | 不强制 |
## 执行顺序(建单前)
1. **实时拉取**云效项目列表Cookie + XSRF
```http
GET /projex/api/workspace/project/search/list
?category=Project&scope=all&toPage=1&pageSize=100
&conditions={"conditionGroups":[[]]}
&extraConditions= + public
&orderBy={"fieldIdentifier":"gmtCreate","format":"input","order":"desc","className":"date"}
&_input_charset=utf-8
```
2. 将结果整理为单选列表:`{name}{customCode}`;选项 id 用 `identifier`spaceId
3. **AskQuestion / Plan 单选**「PJ. 云效项目」;未点选 → **禁止 create**
4. 「批准 Plan」≠ 已选项目Plan 里仍是空选项或写「默认 01_ONEOS」而未点选 → 停。
5. 用户点选后:本轮 apply 全程使用该 `spaceIdentifier`;回报写清项目名 + customCode + spaceId。
6. 拉取成功后可回写 `assets/runtime-ids.json``projects_catalog`(缓存);**缓存不得当作已选项**。
## 无法对应 → 自动重拉一次
「无法对应」任一成立即触发:
| # | 情形 |
|---|---|
| 1 | 口令/预填的项目名、customCode、别名在**当前列表**中 0 命中 |
| 2 | 口令给出的 spaceId / identifier 不在当前列表 |
| 3 | 用户点选的选项 id 在 apply 前校验时已不在列表(列表过期) |
| 4 | 仅命中 `projects_catalog` 缓存、与本次实时列表不一致 |
| 5 | 首次拉取失败后改用了缓存,用户按缓存点选后 create 报项目/空间无效 |
**动作(固定一次):**
1. **立即再调一次**同一 `project/search/list`(强制网络,不用缓存)。
2. 用新列表重新做匹配 / 刷新 Plan 单选选项;可回写 `projects_catalog`
3. 回报注明:`已自动重拉项目列表(因无法对应)`
4. **仍无法对应** → 停,展示最新列表请用户重选;**禁止**再自动拉第 3 次;**禁止**猜一个 spaceId 继续建单。
匹配规则(名/码):忽略大小写;`name` 全等或包含;`customCode` 全等;`name_aliases` 全等。多命中视为无法唯一对应 → 重拉后仍多命中则请用户点选,不自动选定。
## 禁止
- 未询问就写入 `project.spaceIdentifier`(即便 catalog 标了 `suggested`
- 按口令里的「统一运营管理平台」字符串静默映射而不展示列表点选(口令仅作**预填建议**,仍须用户确认点选)
- API 失败时擅自沿用上次默认;应展示 `projects_catalog` 缓存并标明「离线缓存,请确认」,仍须点选;用户确认后若仍无法对应 → 走上一节「自动重拉一次」
- 多项目并行建单却共用一个未确认的 spaceId
- 「无法对应」时循环重拉超过 1 次,或跳过点选直接建单
## 口令预填
```text
记录需求:…;项目=01_ONEOS
```
若口令已含项目名/编号前缀且在实时列表中**唯一命中**Plan 可预勾该选项但仍须用户确认0 命中或多命中 → **先自动重拉一次**再匹配;仍 0/多 → 不预勾,只展示最新列表。
## 脚本
`scripts/list_projects.py`stdout JSON `projects[]`
带查询时:`python3 scripts/list_projects.py --match '01_ONEOS'` —— 0 命中/多命中则自动重拉一次再匹配(`refetched: true`)。

View File

@@ -0,0 +1,58 @@
# 记录需求 · 元字段(优先级 / 标签 / 提交部门 / 提交人)
建单前消费网页 / AutoRDO / 口令中的四类元信息。细则与 `assets/runtime-ids.json` 对齐;**禁止臆造未验证的 fieldIdentifier**。
## 口令形态
```text
记录需求:…;优先级=紧急|高|中|低;标签=…;提交部门=…;提交人=…;推进至=…
```
四字段均可选出现;网页或 AutoRDO 提示里已带的值与口令等价。
## Plan 是否追问
记录需求 **一律**走 [compact-select.md](compact-select.md) 字母表(类型/项目/优先级/标签),即使用户口令已写齐;给出建议压缩串,等用户回 `1a2b3a4d`(或改字母)并「执行」。
| 条件 | 行为 |
|---|---|
| 口令已含类型/项目/优先级/标签 | 对应选项标 ★ + 建议压缩串;**仍须**压缩确认或显式点选 |
| 标签名 0 命中 / 多命中 | **自动重拉一次**标签候选并重生 4.A/B/C…仍失败则停 |
| 仅缺提交部门/提交人 | 压缩 14 确认后,缺则追问或写入描述页脚 |
| 仅缺「推进至」等 | 按既有口令规则;可作 5. 题字母表 |
## 写入策略
### 优先级(已验证)
- 映射:`runtime-ids.json``priority`(紧急 / 高 / 中 / 低)。
- create 时写入 `fieldIdentifier: "priority"`(与 [live-api.md](live-api.md) / `live_create_fast.py` 一致)。
- 未给优先级时Plan 追问;脚本默认「中」仅作既有兜底,口令/网页有值时以用户值为准。
### 标签(已验证)
- 映射:`runtime-ids.json``tags`(按显示名取 tagId
- 标签须 **PATCH** `propertyKey: "tag"`create 带 tag 不落库)。
- 口令/网页给出的标签名若不在候选:按 [compact-select.md](compact-select.md) **自动重拉一次**标签列表并重生选项;仍无则停在 Plan勿猜 ID。
### 提交部门 / 提交人(已验证 · 2026-07-27 · ONEOS-293
| 字段 | fieldIdentifier |
|---|---|
| 提交部门 | `3132597a9718d1c282b7ba5a0c` |
| 提交人 | `9e01269e96f91fbb97d36bf5b3` |
| 规则 | 说明 |
|---|---|
| **写入** | `POST /projex/api/workitem/workitem/field/value/{workitemId}``Content-Type: application/x-www-form-urlencoded`,参数 `fieldValueList` = JSON 数组字符串 `[{"fieldIdentifier","value"}]` |
| **形态** | 均为普通文本 input非人员选择器口令值原样写入 |
| **页脚** | 仍可在描述页脚重复一份,便于检索;**不能替代**字段写入 |
| **计划开始** | 字段 `79`,同一 `field/value` API推荐 `YYYY-MM-DD 12:00:00`。快轨:【交付】/【设计】创建当日写入;【设计】另写计划完成 `80`=`当日 23:59:59` |
| **预计工时** | 字段 `101586` **禁止**直接 PATCH`POST …/time/estimate``spentTime`)登记;删多余用 `DELETE …/time/estimate/{workitemId}/{estimateId}` |
| **实际工时** | `POST …/workitem/time`body **`actualTime`**(非 spentTime+ `gmtStart`/`gmtEnd`epoch ms 字符串);快轨待开发需求默认 **2** |
| **描述更新** | `PATCH …/workitem/{id}/document``{"content","formatType":"RICHTEXT"}` |
| **快轨标签** | 【交付】【设计】建单后 `PATCH propertyKey=tag``propertyValue` 与需求 tagId 一致(多标签逗号拼接) |
## 与描述双段的关系
页脚元信息写在「原始诉求」段末或整篇描述末尾均可,**不得覆盖** `## 产品说明AutoPRD` / `## 工作项编号(系统)` 区块(见 [description-split.md](description-split.md))。

View File

@@ -0,0 +1,63 @@
# 创建迭代并关联交付
产品经理可将已交棒(或已有编号)的多条【交付】任务打进同一云效迭代。
## 口令
```text
创建迭代:版本类型=副;交付任务=ONEOS-a,ONEOS-b,ONEOS-c名称前缀=统一运营管理平台PC端
创建迭代:版本类型=子;交付任务=ONEOS-99名称前缀=统一运营管理平台PC端
```
| 参数 | 规则 |
|---|---|
| 交付任务 | **1..N 个任务编号**(逗号分隔);禁止用标题凑数 |
| 版本类型 | 主 / 副 / 子;未点选则停下询问,禁止默认猜 |
| 名称前缀 | 可选;缺省 `统一运营管理平台PC端`。最终名=`{前缀}{版本号}` |
## 版本号 `V{主}.{副}.{子}`
| 版本类型 | 含义 | 递增 |
|---|---|---|
| **主** | 功能重制 | 主+1副→0子→0V1.3.2→V2.0.0 |
| **副** | 新功能上线 | 副+1子→0V1.3.2→V1.4.0 |
| **子** | bug/优化 | 子+1V1.3.2→V1.3.3 |
### 取基线再递增
1. 拉取当前项目云效迭代列表。
2. 从迭代**名称**解析 `V数字.数字.数字`;旧名 `V数字.数字` 视为 `.0`
3. 同名称前缀内取**最大**版本为基线(主→副→子比较);避免 PC 与小程序串号。
4. 按用户点选类型递增,写入新迭代名称。
5. 无一可解析版本:基线 `V0.0.0` 再递增主→V1.0.0副→V0.1.0子→V0.0.1);或口令显式给起始版本。
禁止:手填与规则冲突的版本号却声称自动生成;禁止用交付标题推断版本类型。
## 创建与关联
| 步骤 | 动作 |
|---|---|
| 1 | 算出新版本 → 拼迭代全名 |
| 2 | 创建迭代(起止日期口令未给则询问或用项目默认,禁止瞎填) |
| 3 | **只挂【交付】**N 个交付任务挂迭代;交付失败不得报完成 |
| 4 | 幂等:同名迭代已存在 → 不新建,补挂尚未关联的交付,回报「复用迭代」 |
| 5 | 回报迭代名、版本号、identifier、已关联交付编号、失败编号 |
**禁止**把需求挂进迭代(需求侧「迭代」字段保持空)。不挂【分析】/【设计】除非口令显式点名。
**不**在本步创建【开发】/【测试】。仍须 Plan 门禁。
### 挂接 API已通 · 校验走 `/extra`
```http
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
{"workitemIdentifier":"{id}","propertyKey":"sprint","propertyValue":"{sprintId}","operateType":"COVER"}
```
校验(详情主接口**不**含 sprint勿用其判空
```http
GET /projex/api/workitem/workitem/{id}/extra?_input_charset=utf-8
result.sprint[].identifier
```
清空误挂的需求迭代:同上 PATCH`propertyValue:""` + `operateType:"COVER"`(或 `CLEAR`)。

View File

@@ -0,0 +1,63 @@
# 标准路径:待处理 → 待开发交棒
人员/状态等常量见 [../assets/runtime-ids.json](../assets/runtime-ids.json)。**项目空间**须按 [project-selection.md](project-selection.md) 点选,禁止默认直指。查重只用任务编号。
## 步骤 0创建需求
| 云效动作 | 落地 |
|---|---|
| 新建产品类需求 | POST 建单;标题 `【新增】`/`【优化】` |
| 需求描述 | **先** AutoRDO 清洗再写入 `## 原始诉求AutoRDO`;本步不写 AutoPRD |
| 默认状态 | **待处理**;不建任务、不改负责人 |
| 可选推进 | 口令点选目标状态;未选则停在待处理 |
## 步骤 1受理 → 已确认
| 云效动作 | 落地 |
|---|---|
| 状态 | 待处理 → **已确认** |
| 任务 | **仍不建**交付/分析/设计 |
若用户只「创建」未受理:只提示「受理后请推进至已确认」,不自动跳。
## 步骤 2分析中
| 对象 | 动作 |
|---|---|
| 【交付】 | 无则新建;标题 `【交付】`+需求标题;**ASSOCIATED→需求**(勿用 PARENT负责人=创建人/产品;**计划开始仅空时写当日**;不写计划完成;描述=`等待设计任务完成后自动填入`;更新编号区块 |
| 【分析】 | 新建;**TASK_SUB→交付**`parent`+`parentIdentifier`+`createWorkitemRelationInfo=TASK_SUB`);交付「子项」须可见;计划开始=当日(仅空时);负责人默认可=创建人;更新编号区块 |
| 需求 | 状态=`分析中` |
## 步骤 3设计中
| 对象 | 动作 |
|---|---|
| 【交付】 | 已存在则按编号复用;没有则补建;**不改交付计划开始**;不写交付计划完成 |
| 【设计】 | 新建;**TASK_SUB→交付**(同分析);计划开始=当日(仅空时);更新编号区块 |
| 【分析】 | **计划完成**=状态更新日;推算阶段日历工时(见 work-hours |
| 需求 | 状态=`设计中` |
## 步骤 4设计完成
| 对象 | 动作 |
|---|---|
| 【设计】 | 计划完成=当日;推算工时;任务→完成态 |
| 需求 | AutoPRD 写入 `## 产品说明`;挂 ZIP+截图;状态=`设计完成` |
| 【交付】 | 不换负责人;不改计划开始;不写计划完成;描述改为 AutoPRD 正文;同样挂附件 |
顺序与失败门禁见 [description-split.md](description-split.md)。
## 步骤 5待开发交棒本 Skill 终点 · 标准路径)
| 对象 | 动作 |
|---|---|
| 需求 | 状态=`待开发` |
| 【交付】 | 按**任务编号**定位;**负责人→何斐**;不改计划开始;不写计划完成 |
| 【分析】/【设计】 | 不新建;不改已有计划开始;前序未收口按步骤 3/4 处理 |
执行 [handoff-and-rollback.md](handoff-and-rollback.md) §交棒门禁。
**不做:** 【开发】/【测试】、仓库、分支、提测。
快轨 / 编号直推见专文。创建迭代见 [sprint.md](sprint.md)。

View File

@@ -0,0 +1,73 @@
# 计划时间与阶段日历工时
适用于【交付】/【分析】/【设计】统一口径。
## 用途
| 对象 | 计划开始→计划完成 |
|---|---|
| 【交付】 | 需求开工→上线全周期(本 Skill **不**写交付计划完成;上线由后续段) |
| 【分析】 | 分析阶段时长 |
| 【设计】 | 设计阶段时长 |
## 计划开始(不可篡改)
| 对象 | 首次写入 | 之后 |
|---|---|---|
| 【交付】 | 首次进入分析中且字段为空 → 当日 | **禁止覆盖** |
| 【分析】 | 首次创建且为空 → 当日 | **禁止覆盖** |
| 【设计】 | 首次创建且为空 → 当日 | **禁止覆盖** |
日期写入形态:中国时区正午 epoch ms 字符串,见 [../assets/runtime-ids.json](../assets/runtime-ids.json) `fields.plan_start`
## 计划完成
| 环节 | 写计划完成的对象 |
|---|---|
| 推进到设计中 | 【分析】= 状态更新日 |
| 推进到设计完成 | 【设计】= 状态更新日 |
| 无单快轨建设计 | 【设计】= 当日(同轮收口) |
| 编号直推收口 | 口令涉及的分析/设计若计划完成为空 → 当日 |
| 上线/关闭 | 【交付】计划完成(**本 Skill 暂不写** |
## 预计工时 = 阶段日历工时Lead Time
有计划完成且已有计划开始时,写入该对象云效「预计工时」:
```text
workdays = 0
从计划开始日到计划完成日(含首尾)逐日:
周六或周日 → 跳过(除非该日是调休补班)
法定放假日 → 跳过
调休补班日(含周末上班)→ 计入
其余周一~周五 → 计入
预计工时(小时) = workdays × 8
```
**禁止**用「(结束日 开始日 + 1× 8」日历天数算法。
### 语义与脚注(强制)
- 正式名称:**阶段日历工时****不是**投入人天/排期负荷。
- 任务描述末尾固定脚注:
`【系统】预计工时=阶段日历工时工作日×8非人力投入预估`
- 回报写「阶段日历工时 Hh」**禁止**写「需投入 Hh」。
- 本 Skill **不自动写**「人力投入预估」。
### 日历数据源
- 使用 [../assets/cn-workday-calendar.json](../assets/cn-workday-calendar.json)(按自然年;跨年须覆盖起止两侧年份)。
- 缺当年日历 → **停下**提示补日历;**禁止**静默按「仅去周末」算完并报成功。
- 计算脚本:[../scripts/workday_hours.py](../scripts/workday_hours.py)
```bash
python3 scripts/workday_hours.py 2026-03-06 2026-03-09
```
缺计划开始则只写结束、不推工时,回报提示。
## 示例
- 开始=周五、结束=下周一(无节假日)→ 五+一 → 16h
- 区间全在法定放假内 → 0h
- 某周日为调休补班且落在区间内 → 该日计入 8h

View File

@@ -0,0 +1,22 @@
# 工作项编号(系统)
## 权威源
需求描述固定区块(机器可解析;人工只读即可):
```markdown
## 工作项编号(系统)
- 交付ONEOS-xx
- 分析ONEOS-yy无则写无
- 设计ONEOS-zz无则写无
```
## 规则
1. **禁止**仅靠本地会话映射当唯一真相。
2. 每次新建/登记交付·分析·设计编号后,**立即 PATCH 更新该区块**(只改本区块,不动 AutoRDO / AutoPRD 正文)。
3. 操作顺序:口令显式编号 > 读本区块 > ASSOCIATED/SUB 反查校验。
4. 三者冲突 → 停下人工;**仍禁止按标题猜**。
5. 本地缓存仅加速,启动以云效该区块为准。
6. 区块出现两个交付编号 → 停止并列号请人合并。
7. 取消需求:关联任务标取消/废止;**不删**本区块(留痕)。

View File

@@ -0,0 +1,221 @@
{
"schema_version": 1,
"skill": "YunxiaoPM",
"verified_at": "2026-07-25",
"note": "YunxiaoPM constants. Project space MUST be user-selected (PJ gate); project.spaceIdentifier is last-known cache only — never auto-apply. See references/project-selection.md.",
"project": {
"selection_mode": "user_pick_required",
"name": null,
"name_aliases": [
"01_ONEOS",
"ONEOS",
"统一运营管理平台",
"统一运营管理平台PC端",
"统一运营管理平台 PC 端"
],
"spaceIdentifier": null,
"customCode": null,
"spaceType": "Project",
"organizationIdentifier": "697c54a19df7fdfa65466405",
"default_sprint_name_prefix": "统一运营管理平台PC端",
"list_api": "GET /projex/api/workspace/project/search/list",
"last_selected": {
"name": "01_ONEOS",
"spaceIdentifier": "1280be963a5a2cc126a4118dca",
"customCode": "ONEOS",
"note": "历史常用项;仅作预填建议,禁止未点选即使用"
},
"refreshed_at": "2026-07-25"
},
"projects_catalog": [
{
"name": "05_羚牛碳资产平台",
"identifier": "ff104a3bce09463da136a97999",
"customCode": "CARBON"
},
{
"name": "06_对外客户项目",
"identifier": "baca8b4d676c5af67e475caec0",
"customCode": "CUST"
},
{
"name": "07_LNBOX",
"identifier": "35e1e915a052379bbdfb993aac",
"customCode": "LNBOX"
},
{
"name": "04_AI应用",
"identifier": "d9002ea72c6c3a1a97b02be750",
"customCode": "AIAPP"
},
{
"name": "03_数据中台",
"identifier": "a801cef5c9a68fa051c07432c7",
"customCode": "DATA"
},
{
"name": "02_小羚羚APP",
"identifier": "db771a2cca07bed43b369af077",
"customCode": "XLLAPP"
},
{
"name": "01_ONEOS",
"identifier": "1280be963a5a2cc126a4118dca",
"customCode": "ONEOS"
},
{
"name": "敏捷研发示例项目",
"identifier": "65eca0c2e16a23939081e19e14",
"customCode": "DEMO"
}
],
"people": {
"wangmian": {
"displayName": "王冕",
"identifier": "6811df000601d2fea60144a9",
"role": "产品创建人/默认负责人"
},
"hefei": {
"displayName": "何斐",
"identifier": "695f0400562f09713f9c3a93",
"role": "待开发交棒【交付】负责人"
}
},
"tags": {
"故障管理": "ceb526a7343995577645317e9a",
"还车应结款": "4204960ce658c94b17abb7c5f6",
"工作台": "b62d21beac55c0b43389915eab",
"交车管理": "b6947b5aca82a8c759612ba039",
"合同管理": "23873be81931cb0dc1bf87a456",
"安全培训": "76988b5f73ef515de5930d59b9",
"证照管理": "11f4c2ec65901a8f3199c81706",
"还车管理": "1e0fce2d6929ff4ac13b310e97"
},
"status": {
"req": {
"待处理": "100005",
"已确认": "32",
"分析中": "154395",
"设计中": "156603",
"设计完成": "307012",
"待开发": "1582fc929d429111b925309493"
},
"task": {
"待处理": "100005",
"已完成": "100014"
},
"transit_api": "POST /projex/api/workitem/workitem/{id}/status/transit",
"fast_handoff_hops": [
"设计完成",
"待开发"
],
"note": "见 references/live-api.md禁止再用 updateStatus"
},
"workitem_types": {
"product_req": {
"name": "产品类需求",
"category": "Req",
"identifier": "9uy29901re573f561d69jn40"
},
"task": {
"name": "任务",
"category": "Task",
"identifier": "ba102e46bc6a8483d9b7f25c"
}
},
"priority": {
"紧急": "646004e97f54bb77fec7b455df",
"高": "95b89e0a524d9693e1f335ffe5",
"中": "fa155d1214f9f8db222d39db3b",
"低": "92924feff9c1085891e7511872"
},
"fields": {
"plan_start": {
"fieldIdentifier": "79",
"name": "计划开始时间",
"value_shape": "YYYY-MM-DD HH:mm:ss China wall time preferred; epoch ms string also accepted",
"example": "2026-07-27 12:00:00",
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
},
"plan_end": {
"fieldIdentifier": "80",
"name": "计划完成时间",
"value_shape": "YYYY-MM-DD HH:mm:ss or epoch ms string",
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
},
"estimated_hours": {
"fieldIdentifier": "101586",
"name": "预计工时",
"note": "不可直接改字段;须工时预估登记",
"create_api": "POST /projex/api/workitem/workitem/time/estimate body spentTime,type,recordUserIdentifier,workitemIdentifier",
"delete_api": "DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}",
"list_api": "GET /projex/api/workitem/workitem/time/estimate/list?workitemIdentifier="
},
"actual_hours": {
"name": "实际工时",
"note": "快轨待开发默认 2",
"create_api": "POST /projex/api/workitem/workitem/time body actualTime,type,recordUserIdentifier,workitemIdentifier,gmtStart,gmtEnd (epoch ms string)",
"list_api": "GET /projex/api/workitem/workitem/time/list?workitemIdentifier=",
"fast_track_default": 2,
"verified_at": "2026-07-27",
"verified_on": "ONEOS-293"
},
"fast_track": {
"req_estimated_hours": 2,
"req_actual_hours": 2,
"design_plan_start_end_same_day": true,
"design_description": "copy_req_document",
"delivery_description": "manual_sync_or_autoprd",
"delivery_design_same_tags_as_req": true,
"design_associated_to_req_after_task_sub": true,
"document_update_api": "PATCH /projex/api/workitem/workitem/{id}/document {content,formatType:RICHTEXT}"
},
"submit_department": {
"fieldIdentifier": "3132597a9718d1c282b7ba5a0c",
"name": "提交部门",
"format": "string input",
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
"verified_at": "2026-07-27",
"verified_on": "ONEOS-293"
},
"submitter": {
"fieldIdentifier": "9e01269e96f91fbb97d36bf5b3",
"name": "提交人",
"format": "string input",
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
"verified_at": "2026-07-27",
"verified_on": "ONEOS-293"
},
"tag": {
"fieldIdentifier": "tag",
"name": "标签",
"propertyKey": "tag"
}
},
"assignee_rules": {
"待开发_交付任务": "hefei",
"分析中_交付与分析": "creator",
"设计中_设计": "creator"
},
"relation": {
"delivery_to_req": "ASSOCIATED",
"stage_to_delivery": "TASK_SUB",
"create_field": "createWorkitemRelationInfo",
"forbid": [
"PARENT_as_关联项",
"ASSOCIATED_only_for_stage_tasks_without_TASK_SUB"
],
"note": "交付必须 ASSOCIATED→需求。分析/设计默认 TASK_SUB→交付子项 tab。二者同 create 互斥。见 references/live-api.md"
},
"delivery_placeholder": "等待设计任务完成后自动填入",
"task_title_prefixes": {
"delivery": "【交付】",
"analysis": "【分析】",
"design": "【设计】"
},
"publish_url": {
"shape": "{baseUrl}/{prototype-id}/index.html",
"forbid_prototypes_prefix": true,
"require_index_html": true
}
}

View File

@@ -0,0 +1,227 @@
#!/usr/bin/env python3
"""拉取云效项目列表(供 YunxiaoPMapp 门禁 PJ 点选。stdout = JSON。
无法对应时自动重拉一次:
python3 scripts/list_projects.py --match '01_ONEOS'
python3 scripts/list_projects.py --match-id 1280be963a5a2cc126a4118dca
"""
from __future__ import annotations
import argparse
import json
import urllib.parse
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any
import requests
ROOT = Path(__file__).resolve().parents[1]
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
ORG = RUNTIME.get("project", {}).get("organizationIdentifier", "697c54a19df7fdfa65466405")
WANG = RUNTIME.get("people", {}).get("wangmian", {}).get("identifier", "6811df000601d2fea60144a9")
ALIASES = [a.lower() for a in (RUNTIME.get("project", {}).get("name_aliases") or [])]
TZ = timezone(timedelta(hours=8))
def load_jar() -> dict[str, str]:
jar: dict[str, str] = {}
try:
import browser_cookie3
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
try:
for c in browser_cookie3.chrome(domain_name=domain):
jar[c.name] = c.value
except Exception:
pass
except Exception:
pass
if not jar.get("XSRF-TOKEN"):
p = Path("/tmp/yunxiao_cookies.json")
if p.exists():
raw = json.loads(p.read_text())
jar = (
raw
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
)
if not jar.get("XSRF-TOKEN"):
raise RuntimeError("缺少 XSRF-TOKEN请先在 Chrome 登录 devops.aliyun.com")
return jar
def fetch_projects() -> list[dict[str, Any]]:
jar = load_jar()
x = jar.get("XSRF-TOKEN", "")
xsrf = urllib.parse.unquote(x) if "%" in x else x
cookie = "; ".join(f"{k}={v}" for k, v in jar.items())
headers = {
"Cookie": cookie,
"x-xsrf-token": xsrf,
"X-XSRF-TOKEN": xsrf,
"Origin": "https://devops.aliyun.com",
"Referer": "https://devops.aliyun.com/projex",
"accept": "application/json",
}
extra = json.dumps(
{
"conditionGroups": [
[
{
"className": "user",
"fieldIdentifier": "users",
"format": "multiList",
"operator": "CONTAINS",
"value": [WANG],
}
],
[
{
"className": "string",
"fieldIdentifier": "scope",
"format": "list",
"operator": "CONTAINS",
"value": ["public"],
}
],
]
},
separators=(",", ":"),
)
params = {
"extraConditions": extra,
"conditions": json.dumps({"conditionGroups": [[]]}, separators=(",", ":")),
"orderBy": json.dumps(
{
"fieldIdentifier": "gmtCreate",
"format": "input",
"order": "desc",
"className": "date",
},
separators=(",", ":"),
),
"scope": "all",
"category": "Project",
"toPage": 1,
"pageSize": 100,
"_input_charset": "utf-8",
}
r = requests.get(
"https://devops.aliyun.com/projex/api/workspace/project/search/list",
headers=headers,
params=params,
timeout=30,
)
r.raise_for_status()
rows = r.json().get("result") or []
return [
{
"name": p.get("name"),
"identifier": p.get("identifier"),
"customCode": p.get("customCode"),
"logicalStatus": p.get("logicalStatus"),
"status": (p.get("status") or {}).get("displayName"),
"scope": p.get("scope"),
}
for p in rows
]
def match_projects(
projects: list[dict[str, Any]],
*,
query: str | None = None,
space_id: str | None = None,
) -> list[dict[str, Any]]:
if space_id:
sid = space_id.strip()
return [p for p in projects if p.get("identifier") == sid]
if not query:
return []
q = query.strip().lower()
hits: list[dict[str, Any]] = []
for p in projects:
name = (p.get("name") or "").lower()
code = (p.get("customCode") or "").lower()
if q == name or q == code or q in name or name in q:
hits.append(p)
continue
if q in ALIASES and (code == "oneos" or "oneos" in name or "运营" in name):
hits.append(p)
# de-dupe by identifier
seen: set[str] = set()
out: list[dict[str, Any]] = []
for p in hits:
i = p.get("identifier") or ""
if i in seen:
continue
seen.add(i)
out.append(p)
return out
def list_projects(
*,
match: str | None = None,
match_id: str | None = None,
) -> dict:
projects = fetch_projects()
payload: dict[str, Any] = {
"fetched_at": datetime.now(TZ).isoformat(),
"organizationIdentifier": ORG,
"count": len(projects),
"projects": projects,
"selection_required": True,
"refetched": False,
"note": "禁止默认直指;须 AskQuestion/Plan 点选后再写入 spaceIdentifier",
}
if not match and not match_id:
return payload
hits = match_projects(projects, query=match, space_id=match_id)
if len(hits) == 1:
payload["matches"] = hits
payload["match_status"] = "unique"
return payload
# 无法对应0 或多)→ 自动重拉一次
projects2 = fetch_projects()
hits2 = match_projects(projects2, query=match, space_id=match_id)
payload["projects"] = projects2
payload["count"] = len(projects2)
payload["refetched"] = True
payload["refetch_reason"] = "无法对应" if len(hits) != 1 else "unexpected"
if len(hits) == 0:
payload["refetch_reason"] = "首次0命中"
elif len(hits) > 1:
payload["refetch_reason"] = "首次多命中"
payload["matches"] = hits2
if len(hits2) == 1:
payload["match_status"] = "unique_after_refetch"
elif len(hits2) == 0:
payload["match_status"] = "none_after_refetch"
payload["note"] = "已自动重拉一次仍无法对应请用户从最新列表点选禁止再拉第3次"
else:
payload["match_status"] = "ambiguous_after_refetch"
payload["note"] = "已自动重拉一次仍多命中;请用户点选;禁止自动选定"
payload["fetched_at"] = datetime.now(TZ).isoformat()
return payload
def main() -> None:
ap = argparse.ArgumentParser(description="YunxiaoPMapp 项目列表 / 匹配(无法对应则重拉一次)")
ap.add_argument("--match", help="按项目名或 customCode 匹配")
ap.add_argument("--match-id", help="按 spaceIdentifier 匹配")
args = ap.parse_args()
print(
json.dumps(
list_projects(match=args.match, match_id=args.match_id),
ensure_ascii=False,
indent=2,
)
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,190 @@
#!/usr/bin/env python3
"""标签候选列表(聚合工作项 tag + runtime未命中可 --match 后自动重拉一次。"""
from __future__ import annotations
import argparse
import json
import urllib.parse
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any
import requests
ROOT = Path(__file__).resolve().parents[1]
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
TZ = timezone(timedelta(hours=8))
def load_jar() -> dict[str, str]:
jar: dict[str, str] = {}
try:
import browser_cookie3
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
try:
for c in browser_cookie3.chrome(domain_name=domain):
jar[c.name] = c.value
except Exception:
pass
except Exception:
pass
if not jar.get("XSRF-TOKEN"):
p = Path("/tmp/yunxiao_cookies.json")
if p.exists():
raw = json.loads(p.read_text())
jar = (
raw
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
)
if not jar.get("XSRF-TOKEN"):
raise RuntimeError("缺少 XSRF-TOKEN")
return jar
def session() -> requests.Session:
jar = load_jar()
x = jar.get("XSRF-TOKEN", "")
xsrf = urllib.parse.unquote(x) if "%" in x else x
s = requests.Session()
s.headers.update(
{
"Cookie": "; ".join(f"{k}={v}" for k, v in jar.items()),
"x-xsrf-token": xsrf,
"X-XSRF-TOKEN": xsrf,
"Origin": "https://devops.aliyun.com",
"Referer": "https://devops.aliyun.com/projex",
"accept": "application/json",
"Content-Type": "application/json",
}
)
return s
def fetch_tags(space_id: str) -> list[dict[str, str]]:
s = session()
by_id: dict[str, str] = {}
for name, tid in (RUNTIME.get("tags") or {}).items():
by_id[tid] = name
body = {
"spaceIdentifier": space_id,
"spaceType": "Project",
"category": "Req",
"toPage": 1,
"pageSize": 100,
"conditions": json.dumps({"conditionGroups": [[]]}),
}
rows = (
s.post(
"https://devops.aliyun.com/projex/api/workitem/workitem/list?_input_charset=utf-8",
json=body,
timeout=30,
)
.json()
.get("result")
or []
)
for row in rows:
for t in row.get("tag") or []:
tid = t.get("identifier")
name = t.get("name") or t.get("displayName")
if tid and name:
by_id[tid] = name
# Task 再扫一页,补标签
body["category"] = "Task"
rows = (
s.post(
"https://devops.aliyun.com/projex/api/workitem/workitem/list?_input_charset=utf-8",
json=body,
timeout=30,
)
.json()
.get("result")
or []
)
for row in rows:
for t in row.get("tag") or []:
tid = t.get("identifier")
name = t.get("name") or t.get("displayName")
if tid and name:
by_id[tid] = name
return [{"name": n, "identifier": i} for i, n in sorted(by_id.items(), key=lambda x: x[1])]
def match_tags(tags: list[dict[str, str]], query: str) -> list[dict[str, str]]:
q = query.strip().lower()
hits = []
for t in tags:
name = (t.get("name") or "").lower()
if q == name or q in name or name in q:
hits.append(t)
return hits
def list_tags(*, space_id: str, match: str | None = None, prefer: str | None = None) -> dict[str, Any]:
tags = fetch_tags(space_id)
# prefer 置顶
if prefer:
prefer_l = prefer.strip().lower()
tags = sorted(
tags,
key=lambda t: (0 if (t.get("name") or "").lower() == prefer_l else 1, t.get("name") or ""),
)
out: dict[str, Any] = {
"fetched_at": datetime.now(TZ).isoformat(),
"spaceIdentifier": space_id,
"count": len(tags),
"tags": tags,
"refetched": False,
"note": "标签未命中须自动重拉一次并重生 4.A/B/C 选项;见 compact-select.md",
}
if not match:
return out
hits = match_tags(tags, match)
if len(hits) == 1:
out["matches"] = hits
out["match_status"] = "unique"
return out
# 无法对应 → 重拉一次
tags2 = fetch_tags(space_id)
if prefer:
prefer_l = prefer.strip().lower()
tags2 = sorted(
tags2,
key=lambda t: (0 if (t.get("name") or "").lower() == prefer_l else 1, t.get("name") or ""),
)
hits2 = match_tags(tags2, match)
out["tags"] = tags2
out["count"] = len(tags2)
out["refetched"] = True
out["refetch_reason"] = "首次0命中" if len(hits) == 0 else "首次多命中"
out["matches"] = hits2
if len(hits2) == 1:
out["match_status"] = "unique_after_refetch"
elif len(hits2) == 0:
out["match_status"] = "none_after_refetch"
out["note"] = "已自动重拉标签列表仍无法对应;请用户点选 4.x禁止再拉第3次"
else:
out["match_status"] = "ambiguous_after_refetch"
out["fetched_at"] = datetime.now(TZ).isoformat()
return out
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--space", required=True, help="spaceIdentifier")
ap.add_argument("--match", help="标签名")
ap.add_argument("--prefer", help="置顶标签名")
args = ap.parse_args()
print(
json.dumps(
list_tags(space_id=args.space, match=args.match, prefer=args.prefer),
ensure_ascii=False,
indent=2,
)
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,660 @@
#!/usr/bin/env python3
"""YunxiaoPM 极速真实建单 v5快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂。"""
from __future__ import annotations
import json
import time
import urllib.parse
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any
try:
import browser_cookie3
except ImportError: # pragma: no cover
browser_cookie3 = None
import requests
ROOT = Path(__file__).resolve().parents[1]
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
STATUS = RUNTIME["status"]["req"]
TASK_STATUS = RUNTIME["status"]["task"]
FAST = RUNTIME.get("fields", {}).get("fast_track") or {}
SPACE = (
RUNTIME.get("project", {}).get("spaceIdentifier")
or (RUNTIME.get("project", {}).get("last_selected") or {}).get("spaceIdentifier")
)
if not SPACE:
raise RuntimeError(
"未选定项目 spaceIdentifier须先走门禁 PJ 点选,或设置 runtime project.last_selected"
)
REQ_TYPE = RUNTIME["workitem_types"]["product_req"]["identifier"]
TASK_TYPE = RUNTIME["workitem_types"]["task"]["identifier"]
HEFEI = RUNTIME["people"]["hefei"]["identifier"]
WANG = RUNTIME["people"].get("wangmian", {}).get("identifier", "6811df000601d2fea60144a9")
PRI = RUNTIME["priority"][""]
TAG_FAULT = RUNTIME.get("tags", {}).get("故障管理", "ceb526a7343995577645317e9a")
PLACEHOLDER = RUNTIME["delivery_placeholder"]
PROTO = "https://prototype.lnoneos.com/vehicle-fault-handling/index.html"
TZ = timezone(timedelta(hours=8))
TODAY = datetime.now(TZ).strftime("%Y-%m-%d")
NOON = f"{TODAY} 12:00:00"
EOD = f"{TODAY} 23:59:59"
NOON_MS = str(
int(datetime.now(TZ).replace(hour=12, minute=0, second=0, microsecond=0).timestamp() * 1000)
)
START_MS = str(
int(datetime.now(TZ).replace(hour=9, minute=0, second=0, microsecond=0).timestamp() * 1000)
)
END_MS = str(
int(datetime.now(TZ).replace(hour=11, minute=0, second=0, microsecond=0).timestamp() * 1000)
)
FAST_EST = int(FAST.get("req_estimated_hours", 2))
FAST_ACT = int(FAST.get("req_actual_hours", 2))
PENDING = STATUS["待处理"]
DESIGN_DONE = STATUS["设计完成"]
PENDING_DEV = STATUS["待开发"]
TASK_DONE = TASK_STATUS["已完成"]
_COOKIE = ""
_XSRF = ""
def load_auth() -> None:
global _COOKIE, _XSRF
jar: dict[str, str] = {}
if browser_cookie3:
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
try:
for c in browser_cookie3.chrome(domain_name=domain):
jar[c.name] = c.value
except Exception:
pass
if not jar:
p = Path("/tmp/yunxiao_cookies.json")
if p.exists():
raw = json.loads(p.read_text())
jar = (
raw
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
)
_COOKIE = "; ".join(f"{k}={v}" for k, v in jar.items())
x = jar.get("XSRF-TOKEN", "")
_XSRF = urllib.parse.unquote(x) if "%" in x else x
if not _XSRF:
raise RuntimeError("缺少 XSRF-TOKEN请先在 Chrome 登录 devops.aliyun.com")
def session() -> requests.Session:
s = requests.Session()
s.headers.update(
{
"Content-Type": "application/json",
"Cookie": _COOKIE,
"x-xsrf-token": _XSRF,
"X-XSRF-TOKEN": _XSRF,
"Origin": "https://devops.aliyun.com",
"Referer": f"https://devops.aliyun.com/projex/project/{SPACE}/req",
"accept": "application/json",
"User-Agent": "YunxiaoPM-live_create_fast/5.0",
"Connection": "keep-alive",
}
)
return s
def api(s: requests.Session, method: str, url: str, body: Any = None) -> dict:
r = s.request(method, url, json=body, timeout=60)
try:
return r.json()
except Exception:
r.raise_for_status()
raise
def create(s: requests.Session, payload: dict) -> dict:
url = "https://devops.aliyun.com/projex/api/workitem/workitem?_input_charset=utf-8"
j = api(s, "POST", url, payload)
r = j.get("result") or {}
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
return r
j = api(s, "PUT", url, payload)
r = j.get("result") or {}
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
return r
raise RuntimeError(f"create failed: {j}")
def get(s: requests.Session, wid: str) -> dict:
return api(
s,
"GET",
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
)["result"]
def apply_tag(s: requests.Session, wid: str, tag_id: str = TAG_FAULT) -> None:
j = api(
s,
"PATCH",
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
{
"workitemIdentifier": wid,
"propertyKey": "tag",
"propertyValue": tag_id,
"operateType": "COVER",
},
)
if j.get("code") != 200:
raise RuntimeError(f"tag failed {wid}: {j}")
def set_document(s: requests.Session, wid: str, html: str) -> None:
j = api(
s,
"PATCH",
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/document?_input_charset=utf-8",
{"content": html, "formatType": "RICHTEXT"},
)
if j.get("code") != 200 or j.get("errorMsg"):
raise RuntimeError(f"document failed {wid}: {j}")
def set_fields(s: requests.Session, wid: str, pairs: list[tuple[str, str]]) -> None:
data = urllib.parse.urlencode(
{
"fieldValueList": json.dumps(
[{"fieldIdentifier": k, "value": v} for k, v in pairs], ensure_ascii=False
)
}
)
r = s.post(
f"https://devops.aliyun.com/projex/api/workitem/workitem/field/value/{wid}?_input_charset=utf-8",
data=data,
headers={"Content-Type": "application/x-www-form-urlencoded"},
timeout=60,
)
j = r.json()
if j.get("code") != 200:
raise RuntimeError(f"field/value failed {wid}: {j}")
def set_estimate_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
est = api(
s,
"GET",
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/list?workitemIdentifier={wid}",
).get("result") or []
for row in est:
eid = row.get("identifier")
if eid:
api(
s,
"DELETE",
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/{wid}/{eid}",
)
j = api(
s,
"POST",
"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate?_input_charset=utf-8",
{
"workitemIdentifier": wid,
"spentTime": hours,
"type": "develop",
"description": "快轨默认预计工时",
"recordUserIdentifier": user,
"forCreate": False,
"containsRestDay": False,
},
)
if j.get("code") != 200:
raise RuntimeError(f"estimate failed {wid}: {j}")
def set_actual_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
j = api(
s,
"POST",
"https://devops.aliyun.com/projex/api/workitem/workitem/time?_input_charset=utf-8",
{
"workitemIdentifier": wid,
"actualTime": hours,
"type": "develop",
"description": "快轨默认实际工时",
"recordUserIdentifier": user,
"gmtStart": START_MS,
"gmtEnd": END_MS,
},
)
if j.get("code") != 200 or not j.get("result"):
raise RuntimeError(f"actual time failed {wid}: {j}")
def try_associate_to_req(s: requests.Session, stage_id: str, req_id: str) -> bool:
"""建后补 ASSOCIATED→需求。Cookie 下常失败,成功返回 True。"""
bodies = [
{"relationIdentifier": "ASSOCIATED", "toWorkitemIdentifier": req_id},
{
"relationIdentifier": "ASSOCIATED",
"fromWorkitemIdentifier": stage_id,
"toWorkitemIdentifier": req_id,
},
]
for body in bodies:
for url in (
f"https://devops.aliyun.com/projex/api/workitem/workitem/{stage_id}/relation/record?_input_charset=utf-8",
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{stage_id}/relation/record?_input_charset=utf-8",
):
j = api(s, "POST", url, body)
if j.get("code") == 200 and j.get("result") not in (None, False):
if not (isinstance(j.get("result"), dict) and j["result"].get("status") in (404, 405)):
rows = list_associated(s, stage_id)
if req_id in {r.get("identifier") for r in rows}:
return True
return False
def transit(s: requests.Session, wid: str, from_status: str, to_status: str) -> None:
if from_status == to_status:
return
j = api(
s,
"POST",
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/status/transit?_input_charset=utf-8",
{"fromStatus": from_status, "toStatus": to_status},
)
if not (j.get("code") == 200 and j.get("result") is True):
raise RuntimeError(f"transit {wid} {from_status}->{to_status}: {j}")
def md_to_html(md: str) -> str:
parts = []
for line in md.splitlines():
if line.startswith("## "):
parts.append(f"<h2>{line[3:]}</h2>")
elif line.startswith("### "):
parts.append(f"<h3>{line[4:]}</h3>")
elif line.startswith("- "):
parts.append(f"<p>• {line[2:]}</p>")
elif line.strip():
parts.append(f"<p>{line}</p>")
return "".join(parts)
def req_document_html(s: requests.Session, rid: str) -> str:
w = get(s, rid)
return ((w.get("document") or {}).get("content") or w.get("description") or "").strip()
def req_payload(subject: str, html: str) -> dict:
return {
"subject": subject,
"description": html,
"formatType": "RICHTEXT",
"document": {"content": html, "formatType": "RICHTEXT"},
"spaceIdentifier": SPACE,
"space": SPACE,
"spaceType": "Project",
"workitemTypeIdentifier": REQ_TYPE,
"workitemType": REQ_TYPE,
"categoryIdentifier": "Req",
"category": "Req",
"assignedTo": WANG,
"fieldValueList": [
{"fieldIdentifier": "priority", "value": PRI},
{"fieldIdentifier": "assignedTo", "value": WANG},
],
"attachmentIdList": [],
"cloneFrom": None,
"createWorkitemRelationList": [],
}
def task_payload(
subject: str,
html: str,
assignee: str,
*,
plan_start: bool = True,
associated_req: str | None = None,
parent_delivery: str | None = None,
) -> dict:
fvl = [
{"fieldIdentifier": "priority", "value": PRI},
{"fieldIdentifier": "assignedTo", "value": assignee},
]
if plan_start:
fvl.append({"fieldIdentifier": "79", "value": NOON_MS})
payload: dict[str, Any] = {
"subject": subject,
"description": html,
"formatType": "RICHTEXT",
"spaceIdentifier": SPACE,
"space": SPACE,
"spaceType": "Project",
"workitemTypeIdentifier": TASK_TYPE,
"workitemType": TASK_TYPE,
"categoryIdentifier": "Task",
"category": "Task",
"assignedTo": assignee,
"fieldValueList": fvl,
"attachmentIdList": [],
"cloneFrom": None,
}
if parent_delivery:
payload["parent"] = parent_delivery
payload["parentIdentifier"] = parent_delivery
payload["createWorkitemRelationInfo"] = {
"relatedWorkitemIdentifier": parent_delivery,
"relatedToRelationIdentifier": "TASK_SUB",
}
else:
if not associated_req:
raise ValueError("associated_req required for delivery: ASSOCIATED→需求")
payload["createWorkitemRelationInfo"] = {
"relatedWorkitemIdentifier": associated_req,
"relatedToRelationIdentifier": "ASSOCIATED",
}
return payload
def list_associated(s: requests.Session, wid: str) -> list[dict]:
j = api(
s,
"GET",
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{wid}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true",
)
return j.get("result") or []
def assert_associated_to_req(s: requests.Session, wid: str, req_id: str, label: str) -> None:
rows = list_associated(s, wid)
ids = {r.get("identifier") for r in rows}
if req_id not in ids:
raise RuntimeError(
f"{label} 关联项未挂需求:期望 {req_id},实际 {[r.get('serialNumber') for r in rows]}"
)
AUTO_RDO = """## 原始诉求AutoRDO
运维需在故障处置页承接机器人上报的故障,完成处置、挂起与归档,并保留证据链;工作台相关统计口径需与处置页一致
待确认:
- 本期是否含真实短信/邮件通道(现口径一般为演示模板)
## 工作项编号(系统)
- 交付:待建
- 分析:待建
- 设计:待建
"""
def summarize_from_create(w: dict, *, status: str, assignee_name: str) -> dict:
return {
"serial": w.get("serialNumber"),
"id": w.get("identifier"),
"subject": w.get("subject"),
"status": status,
"assignee": assignee_name,
"parent": w.get("parentIdentifier"),
}
def build_normal() -> dict:
t0 = time.perf_counter()
s = session()
title = "【新增】故障处置YunxiaoPMapp标准·极速v2"
req = create(s, req_payload(title, md_to_html(AUTO_RDO + f"\n原型:{PROTO}\n")))
rid = req["identifier"]
with ThreadPoolExecutor(max_workers=2) as pool:
f_tag_r = pool.submit(apply_tag, session(), rid)
f_deliv = pool.submit(
create,
session(),
task_payload(
f"【交付】{title}",
f"<p>{PLACEHOLDER}</p>",
HEFEI,
associated_req=rid,
),
)
deliv = f_deliv.result()
f_tag_r.result()
did = deliv["identifier"]
with ThreadPoolExecutor(max_workers=3) as pool:
f_tag_d = pool.submit(apply_tag, session(), did)
f_ana = pool.submit(
create,
session(),
task_payload(
f"【分析】{title}",
"<p>分析阶段:故障处置台账、挂起归档与证据链。</p>",
WANG,
associated_req=rid,
parent_delivery=did,
),
)
f_des = pool.submit(
create,
session(),
task_payload(
f"【设计】{title}",
f"<p>设计阶段:对齐原型 {PROTO}</p>",
WANG,
associated_req=rid,
parent_delivery=did,
),
)
ana = f_ana.result()
des = f_des.result()
f_tag_d.result()
with ThreadPoolExecutor(max_workers=3) as pool:
list(
as_completed(
[
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
pool.submit(transit, session(), ana["identifier"], PENDING, TASK_DONE),
pool.submit(transit, session(), des["identifier"], PENDING, TASK_DONE),
]
)
)
transit(s, rid, DESIGN_DONE, PENDING_DEV)
return {
"path": "normal",
"elapsed_s": round(time.perf_counter() - t0, 3),
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
"analysis": summarize_from_create(ana, status="已完成", assignee_name="王冕"),
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
}
def build_fast(
*,
tag_id: str = TAG_FAULT,
has_prototype: bool = True,
delivery_html: str | None = None,
) -> dict:
"""无单快轨。
- 设计描述 = 需求 document
- 交付描述 = 手工同步需求正文(无原型)或传入 AutoPRD HTML禁止无故占位
- 设计 79/80=当日;交付 79=当日
- 需求/交付/设计同标签
- 需求预计/实际工时各 2
- 设计 TASK_SUB→交付后尝试 ASSOCIATED→需求
"""
t0 = time.perf_counter()
s = session()
title = "【新增】故障处置YunxiaoPM快轨·极速v5"
req_html = md_to_html(AUTO_RDO + (f"\n原型:{PROTO}\n" if has_prototype else "\n"))
req = create(s, req_payload(title, req_html))
rid = req["identifier"]
# 以落库 document 为准(与手动建需后读需求一致)
req_html = req_document_html(s, rid) or req_html
if delivery_html:
deliv_html = delivery_html
desc_source = "autoprd"
elif req_html.strip():
deliv_html = req_html
desc_source = "manual_sync"
else:
deliv_html = f"<p>{PLACEHOLDER}</p>"
desc_source = "placeholder"
with ThreadPoolExecutor(max_workers=2) as pool:
f_tag_r = pool.submit(apply_tag, session(), rid, tag_id)
f_deliv = pool.submit(
create,
session(),
task_payload(
f"【交付】{title}",
deliv_html,
HEFEI,
associated_req=rid,
),
)
deliv = f_deliv.result()
f_tag_r.result()
did = deliv["identifier"]
with ThreadPoolExecutor(max_workers=2) as pool:
f_tag_d = pool.submit(apply_tag, session(), did, tag_id)
f_des = pool.submit(
create,
session(),
task_payload(
f"【设计】{title}",
req_html,
WANG,
parent_delivery=did,
),
)
des = f_des.result()
f_tag_d.result()
des_id = des["identifier"]
apply_tag(s, des_id, tag_id)
# 计划时间设计起止当日交付开始当日create 已带 79再 field/value 加固)
set_fields(s, des_id, [("79", NOON), ("80", EOD)])
set_fields(s, did, [("79", NOON)])
# 设计关联项补挂需求(可能失败,回报 risk
design_assoc_ok = try_associate_to_req(s, des_id, rid)
with ThreadPoolExecutor(max_workers=2) as pool:
list(
as_completed(
[
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
pool.submit(transit, session(), des_id, PENDING, TASK_DONE),
]
)
)
transit(s, rid, DESIGN_DONE, PENDING_DEV)
set_estimate_hours(s, rid, FAST_EST)
set_actual_hours(s, rid, FAST_ACT)
risk = None
if desc_source == "placeholder":
risk = "交付描述仍为占位"
if not design_assoc_ok:
risk = (risk + "" if risk else "") + "设计 ASSOCIATED→需求补挂失败Cookie须 UI/OpenAPI 兜底"
return {
"path": "fast",
"elapsed_s": round(time.perf_counter() - t0, 3),
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
"analysis": None,
"delivery_desc_source": desc_source,
"design_associated_ok": design_assoc_ok,
"risk": risk,
}
def main() -> None:
auth0 = time.perf_counter()
load_auth()
auth_s = round(time.perf_counter() - auth0, 3)
wall0 = time.perf_counter()
with ThreadPoolExecutor(max_workers=2) as pool:
f_fast = pool.submit(build_fast)
f_normal = pool.submit(build_normal)
fast = f_fast.result()
normal = f_normal.result()
build_s = round(time.perf_counter() - wall0, 3)
s = session()
assert_associated_to_req(s, normal["delivery"]["id"], normal["req"]["id"], "normal.delivery")
assert_associated_to_req(s, fast["delivery"]["id"], fast["req"]["id"], "fast.delivery")
def assert_sub(delivery_id: str, child_id: str, label: str) -> None:
rows = api(
s,
"GET",
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{delivery_id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true",
).get("result") or []
ids = {r.get("identifier") for r in rows}
if child_id not in ids:
raise RuntimeError(
f"{label} 未出现在交付子项:期望 {child_id},实际 {[r.get('serialNumber') for r in rows]}"
)
assert_sub(normal["delivery"]["id"], normal["analysis"]["id"], "normal.analysis")
assert_sub(normal["delivery"]["id"], normal["design"]["id"], "normal.design")
assert_sub(fast["delivery"]["id"], fast["design"]["id"], "fast.design")
verify = {
"normal_req": get(s, normal["req"]["id"])["status"]["displayName"],
"fast_req": get(s, fast["req"]["id"])["status"]["displayName"],
"normal_delivery_assignee": (
get(s, normal["delivery"]["id"]).get("assignedTo") or {}
).get("displayName"),
"fast_delivery_assignee": (get(s, fast["delivery"]["id"]).get("assignedTo") or {}).get(
"displayName"
),
"delivery_associated_ok": True,
"stage_tasks_as_sub_ok": True,
"fast_design_associated_ok": fast.get("design_associated_ok"),
}
out = {
"normal": normal,
"fast": fast,
"verify": verify,
"auth_elapsed_s": auth_s,
"wall_elapsed_s": build_s,
"created_at": datetime.now(TZ).isoformat(),
"mode": "live_create_fast_v5_fast_track_rules",
"opts": {
"create_includes_plan_start": True,
"skip_plan_end_on_create": True,
"tracked_transit_no_get": True,
"delivery_assignee_hefei_at_create": True,
"overlap_tag_with_create": True,
"fast_req_hours": f"{FAST_EST}+{FAST_ACT}",
"relation": "delivery ASSOCIATED→req; analysis/design TASK_SUB→delivery; design post ASSOCIATED→req",
"http": "requests.Session keep-alive",
},
}
Path("/tmp/yunxiao_pmapp_fast_v2_result.json").write_text(
json.dumps(out, ensure_ascii=False, indent=2)
)
print(json.dumps(out, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python3
"""Compute YunxiaoPMapp stage calendar hours = workdays × 8.
Usage:
python3 workday_hours.py YYYY-MM-DD YYYY-MM-DD
python3 workday_hours.py YYYY-MM-DD YYYY-MM-DD --calendar /path/to/cn-workday-calendar.json
"""
from __future__ import annotations
import argparse
import json
import sys
from datetime import date, datetime, timedelta
from pathlib import Path
def parse_day(s: str) -> date:
return datetime.strptime(s, "%Y-%m-%d").date()
def load_calendar(path: Path) -> dict:
data = json.loads(path.read_text(encoding="utf-8"))
years = data.get("years") or {}
holidays: set[str] = set()
makeup: set[str] = set()
for _y, block in years.items():
holidays.update(block.get("holidays") or [])
makeup.update(block.get("workdays_on_weekend") or [])
return {"holidays": holidays, "makeup": makeup, "years": set(years.keys())}
def ensure_years_covered(start: date, end: date, years: set[str]) -> None:
y = start.year
while y <= end.year:
if str(y) not in years:
raise SystemExit(
f"缺少 {y} 年日历:请在 assets/cn-workday-calendar.json 补全后再计算。"
"禁止仅去周末静默估算。"
)
y += 1
def is_workday(d: date, holidays: set[str], makeup: set[str]) -> bool:
key = d.isoformat()
if key in holidays:
return False
if key in makeup:
return True
return d.weekday() < 5 # Mon=0 .. Fri=4
def count_workdays(start: date, end: date, holidays: set[str], makeup: set[str]) -> int:
if end < start:
raise SystemExit("结束日早于开始日")
n = 0
cur = start
while cur <= end:
if is_workday(cur, holidays, makeup):
n += 1
cur += timedelta(days=1)
return n
def main() -> None:
parser = argparse.ArgumentParser(description="阶段日历工时 = 工作日×8")
parser.add_argument("start", help="计划开始 YYYY-MM-DD")
parser.add_argument("end", help="计划完成 YYYY-MM-DD")
parser.add_argument(
"--calendar",
default=str(Path(__file__).resolve().parent.parent / "assets" / "cn-workday-calendar.json"),
help="日历 JSON 路径",
)
args = parser.parse_args()
start = parse_day(args.start)
end = parse_day(args.end)
cal = load_calendar(Path(args.calendar))
ensure_years_covered(start, end, cal["years"])
days = count_workdays(start, end, cal["holidays"], cal["makeup"])
hours = days * 8
out = {
"start": start.isoformat(),
"end": end.isoformat(),
"workdays": days,
"stage_calendar_hours": hours,
"label": "阶段日历工时工作日×8非人力投入预估",
}
print(json.dumps(out, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,63 @@
# 标准路径:待处理 → 待开发交棒
项目常量见 [../assets/runtime-ids.json](../assets/runtime-ids.json)。查重只用任务编号。
## 步骤 0创建需求
| 云效动作 | 落地 |
|---|---|
| 新建产品类需求 | POST 建单;标题 `【新增】`/`【优化】` |
| 需求描述 | **先** AutoRDO 清洗再写入 `## 原始诉求AutoRDO`;本步不写 AutoPRD |
| 默认状态 | **待处理**;不建任务、不改负责人 |
| 可选推进 | 口令点选目标状态;未选则停在待处理 |
## 步骤 1受理 → 已确认
| 云效动作 | 落地 |
|---|---|
| 状态 | 待处理 → **已确认** |
| 任务 | **仍不建**交付/分析/设计 |
若用户只「创建」未受理:只提示「受理后请推进至已确认」,不自动跳。
## 步骤 2分析中
| 对象 | 动作 |
|---|---|
| 【交付】 | 无则新建;标题 `【交付】`+需求标题;**ASSOCIATED→需求**(勿用 PARENT负责人=创建人/产品;**计划开始仅空时写当日**;不写计划完成;描述=`等待设计任务完成后自动填入`;更新编号区块 |
| 【分析】 | 新建;**TASK_SUB→交付**`parent`+`parentIdentifier`+`createWorkitemRelationInfo=TASK_SUB`);交付「子项」须可见;计划开始=当日(仅空时);负责人默认可=创建人;更新编号区块 |
| 需求 | 状态=`分析中` |
## 步骤 3设计中
| 对象 | 动作 |
|---|---|
| 【交付】 | 已存在则按编号复用;没有则补建;**不改交付计划开始**;不写交付计划完成 |
| 【设计】 | 新建;**TASK_SUB→交付**(同分析);计划开始=当日(仅空时);更新编号区块 |
| 【分析】 | **计划完成**=状态更新日;推算阶段日历工时(见 work-hours |
| 需求 | 状态=`设计中` |
## 步骤 4设计完成
| 对象 | 动作 |
|---|---|
| 【设计】 | 计划完成=当日;推算工时;任务→完成态 |
| 需求 | AutoPRD 写入 `## 产品说明`;挂 ZIP+截图;状态=`设计完成` |
| 【交付】 | 不换负责人;不改计划开始;不写计划完成;描述改为 AutoPRD 正文;同样挂附件 |
顺序与失败门禁见 [description-split.md](description-split.md)。
## 步骤 5待开发交棒本 Skill 终点 · 标准路径)
| 对象 | 动作 |
|---|---|
| 需求 | 状态=`待开发` |
| 【交付】 | 按**任务编号**定位;**负责人→何斐**;不改计划开始;不写计划完成 |
| 【分析】/【设计】 | 不新建;不改已有计划开始;前序未收口按步骤 3/4 处理 |
执行 [handoff-and-rollback.md](handoff-and-rollback.md) §交棒门禁。
**不做:** 【开发】/【测试】、仓库、分支、提测。
快轨 / 编号直推见专文。创建迭代见 [sprint.md](sprint.md)。

View File

@@ -1,146 +1,108 @@
---
name: oneos-autoprd
description: >-
Generates and keeps in sync OneOS AutoPRD (PM-facing requirements) plus Axhub
Make annotation directory Markdown/PRD; on 需求定稿/定稿/确认定稿/本次定稿 appends
functional release changelog below the PRD since last baseline. When a Yunxiao
requirement advances to 分析中/设计中/待开发, creates a same-titled linked task
(tag+create-time follow the requirement; 分析中/设计中 assignee=creator, 待开发
assignee=何斐). Use eagerly for prototypes, AutoPRD, or Yunxiao requirement
description/更新内容/stage advance—do not skip annotation sync, 定稿 changelog,
or stage-task creation.
OneOS AutoPRD: generates PM-facing requirements (总览/目标/边界/角色/用户故事
起点→运作→闭环/故事点/正逆向/流程图/关键逻辑/状态/风险/交付) and syncs Axhub Make
annotation PRD. On 需求定稿/本轮定稿 appends functional changelog with auto
V主.副.子 (user 主/副/子 override wins). With YunxiaoPMapp design-complete,
writes Markdown into 【交付】 by task number (not at create; placeholder until then).
Use for AutoPRD, prototypes, 产品说明, 本轮定稿. Never create same-titled stage
tasks; never load yunxiao-requirement-lifecycle—cloud combo is YunxiaoPMapp only.
---
# OneOS AutoPRD
# AutoPRDoneos-autoprd
为 OneOS 业务模块生成**产品经理可读、可评审、可排期**的需求说明,并**自动挂到 Axhub Make 标注工具 → 原型目录**。
另支持:**需求定稿**时汇总功能/逻辑变更记录;与云效组合时提供「需求说明 + 更新内容」;需求进入**分析中 / 设计中 / 待开发**时**自动创建与需求同名的关联任务**(规则见下,写在本 Skill不改云效 Skill
另支持:**本轮定稿 / 需求定稿**时汇总功能变更并**自动递增 PRD 版本号**;与 **`$YunxiaoPMapp`** 组合时,在**设计完成**(或显式同步交付)把 Markdown 写入【交付】任务描述
颗粒度对齐「保险采购」全模块 PRD讲清做什么、谁用、故事点、正逆向、流程图与关键业务逻辑**不**表结构、接口、字段代码名、文件路径、实现清单
**禁止加载** `yunxiao-requirement-lifecycle`。云效状态机与【交付】/【分析】/【设计】树**只**由 YunxiaoPMapp 负责;本 Skill **不**建同名无前缀阶段任务
颗粒度:讲清做什么、谁用、故事点、正逆向、流程图与关键业务逻辑;**不写**表结构、接口、字段代码名、文件路径、实现清单。
## 何时使用(含自动触发)
**主动调用**
**主动调用**
- AutoPRD、OneOS 需求说明、整模块 PRD、故事点 + 流程图
- AutoPRD、OneOS 需求说明、整模块 PRD、故事点 + 流程图、产品说明
**改原型时必须自动跟进(全局规则)**
**改原型时必须自动跟进**
- 正在修改 `src/prototypes/<id>/` 下页面、交互、文案、判定、验收相关内容
- 同一轮交付内同步更新 PRD Markdown + 标注目录,不得只改代码
- 修改 `src/prototypes/<id>/` 下页面、交互、文案、判定、验收相关内容
- 同一轮同步更新 PRD Markdown + 标注目录**纯样式且无产品语义变化可跳过全量重写**
**需求定稿时(强制)**
- 用户回复含`需求定稿` / `定稿` / `确认定稿` / `本次定稿`
- 执行 [references/release-changelog.md](references/release-changelog.md)第 10 章 + 更新基线
- 关键字`需求定稿` / `定稿` / `确认定稿` / `本次定稿` / **`本轮定稿`**
- 执行 [references/release-changelog.md](references/release-changelog.md):第 10 章 + `prdVersion` 基线
**云效建需求 / 完善需求时(强制组合)**
**与 YunxiaoPMapp 组合(强制 · 唯一云效组合)**
- `$yunxiao-requirement-lifecycle` 一起使用时:先跑本 Skill再写云效描述
- **需求说明** ← PRD 正文(或浓缩交付口径 + 关键章节)
- **更新内容** ← 第 10 章中**自上次定稿以来**的条目(无增量则「首版定稿 / 本轮无功能增量」)
**云效需求推进至分析中 / 设计中 / 待开发时(强制)**
- 无论口令来自本 Skill 还是云效 Skill只要本轮把需求推到上述状态就执行 [references/yunxiao-stage-tasks.md](references/yunxiao-stage-tasks.md)
- 自动建**与需求同名**的任务并正式关联;标签与创建时间口径沿用需求;分析中/设计中负责人=创建人,待开发负责人=**何斐**
不要用本 Skill 替代:需求探索访谈、设计比稿、纯样式微调(无产品语义变化时可跳过全量重写)。
- 设计完成或完善「产品说明」:先本 Skill 落盘 MD再由 YunxiaoPMapp / 本 Skill 按 [yunxiao-description.md](references/yunxiao-description.md) 写入需求 `## 产品说明AutoPRD`**不覆盖** `## 原始诉求AutoRDO` / `## 工作项编号(系统)`
- **创建【交付】时不写 PRD 正文**(占位由 YunxiaoPMapp 写入);设计完成或口令「同步交付说明」时按 [yunxiao-delivery-sync.md](references/yunxiao-delivery-sync.md) 用任务**编号**回填【交付】
- 入库前聊天/录音清洗:先 `$AutoRDO`,再 YunxiaoPMapp 记录需求
## 工作流
### 主流程(写/同步 PRD
1. **定模块**确认 OneOS 模块名与 `src/prototypes/<prototype-id>/`
1. **定模块**OneOS 模块名与 `src/prototypes/<prototype-id>/`
2. **读上下文(只取产品语义)**
- 用户说明、已确认口径、原型标注、`.spec/`、业务条线说明(`lines.ts`
- 忽略实现细节;字段名/接口改写成业务语言。
3. **收敛边界**:做什么 / 不做什么、外部依赖、与其它模块关系。
4. **按模板成文**下方「输出结构」;缺关键信息最多问 12 个问题,其余写「假设」
5. **落盘 + 标注同步(强制)** [references/annotation-sync.md](references/annotation-sync.md)。
4. **按模板成文**「输出结构」与 [references/template.md](references/template.md)
5. **落盘 + 标注同步(强制)** — [references/annotation-sync.md](references/annotation-sync.md)。
| 顺序 | 动作 |
|------|------|
| A | 写/更新 `src/prototypes/<id>/.spec/requirements-prd.md` |
| B | 写/更新 `src/resources/prd/<id>-autoprd.md` |
| C | 更新 `annotation-source.json` **顶层** `directory.nodes`PRD 全文 + 推荐分章);禁止只写 `data.directory` |
| C | 更新 `annotation-source.json` **顶层** `directory.nodes`PRD 全文 + 推荐分章) |
| D | 若存在 `scripts/sync-annotation-directory.mjs`,执行之 |
6. **交付说明**:路径、标注目录入口、故事点合计、开放问题/假设。
6. **交付说明**:路径、标注入口、故事点合计、开放问题/假设。
### 定稿流程(关键字触发)
### 定稿流程
见 [references/release-changelog.md](references/release-changelog.md)。摘要:
见 [references/release-changelog.md](references/release-changelog.md)。含自动 `V主.副.子`**用户显式指定主/副/子时以用户为准**。
1. 读 PRD + `.spec/autoprd-baseline.json`
2. 汇总自上次定稿以来的**功能/逻辑**变更(排除样式/UI/表结构)
3. 追加到 `## 10. 功能变更记录`(最新在上)
4. 更新基线 JSON + 标注目录
5. 若同时发云效:本次定稿块 →「更新内容」;旧段 →「更新内容·历史」
### 云效需求「产品说明」(与 YunxiaoPMapp 双段模板)
### 云效交接格式(给 yunxiao skill 直接粘贴)
见 [references/yunxiao-description.md](references/yunxiao-description.md)。
```markdown
## 原型链接
<对象存储或预览 URL>
### 云效【交付】回填(设计完成 · 非创建时)
## 需求说明
<AutoPRD 正文或交付口径 + 必要章节>
## 更新内容
<第 10 章本次定稿块;无则「首版定稿」或「本轮无功能/逻辑增量」>
## 更新内容·历史
<以往更新内容倒序,勿删除>
```
### 云效阶段任务(状态推进时强制)
见 [references/yunxiao-stage-tasks.md](references/yunxiao-stage-tasks.md)。摘要:
| 需求状态 | 任务标签 | 负责人 | 标题 |
|----------|----------|--------|------|
| 分析中 | 分析 | 需求创建人 | 与需求同名 |
| 设计中 | 设计 | 需求创建人 | 与需求同名 |
| 待开发 | 交付(或开发) | 何斐 | 与需求同名 |
正式关联需求;创建时间口径沿用需求;同阶段未取消任务不重复建。
见 [references/yunxiao-delivery-sync.md](references/yunxiao-delivery-sync.md)。
## 写作硬约束
**必须写**
**必须写(映射用户概要)**
- 一句话定位 + 目标 / 非目标
- 模块边界(含 mermaid 总览更好)
- 角色与目标(角色名优先对齐业务条线说明)
- **用户故事**(业务条线说明口径)+ Epic 级**故事点SP**粗估
- 分功能**正向**与**逆向/边界**
- 至少 12 个 **mermaid** 流程图
- **关键业务逻辑**(业务话)
- 验收清单 + 「交付口径」一段话
- 定稿后:**功能变更记录**(第 10 章)
| 概要能力 | 落在章节 |
|---|---|
| 总览 | §1 一句话与目标 |
| 目标 / 边界 | §12 |
| 角色 | §3 |
| 用户故事(起点→运作→闭环)+ 故事点 | §4 |
| 正逆向流程 | §5 |
| 关键逻辑 / 状态 / 风险 | §6及验收相关 |
| 流程图 | §7 |
| 交付 | §9 交付口径 |
| 定稿变更 | §10 |
另:验收清单 §8对象存储预览链接形态 `{baseUrl}/{prototype-id}/index.html`(禁止加 `prototypes/` 前缀、禁止去掉 `index.html`)。
**禁止写**
- 数据库表、字段名、接口路径、代码路径、组件名、存储 key
- 研发实现指令(可写「正式环境由审批中心回写」这类业务依赖)
- 在变更记录里写样式/UI/表结构优化
- 变更记录里的样式/UI/表结构优化
- 引导加载 `yunxiao-requirement-lifecycle` 或「同名阶段任务」建单
## 用户故事口径(强制 · 对齐业务条线说明)
真相源:原型 **业务条线说明**`lease-business-line-overview` / `lines.ts`)。
每条能力用「责任部门 → **起点****怎么运作****闭环**」叙述;**不要**用「作为…我希望…」宽表作主叙述。
| 块 | 写什么 |
|----|--------|
| 角色 | 谁负责、谁协同 |
| 起点 | 谁在什么前提下启动 |
| 怎么运作 | 有序步骤,含跨角色协作 |
| 关键结果 | 可选标签 |
| 闭环 | 业务终点与可追溯性 |
可选:`US-xx`、压缩句「作为…我想…以便…」、规模 S/M/L 或 SP仅排期不替代主叙述
真相源:业务条线说明(`lease-business-line-overview` / `lines.ts`)。
主叙述:**起点 → 怎么运作 → 闭环**(不要用「作为…我希望…」宽表作主叙述
## 输出结构
@@ -158,26 +120,27 @@ description: >-
## 7. 总览流程图
## 8. 验收清单
## 9. 交付口径
## 10. 功能变更记录 ← 定稿维护;日常改原型不强制每改必写
## 10. 功能变更记录 ← 定稿维护;含 V主.副.子
```
## 质量自检
- [ ] 产品经理不看代码也能评审
- [ ] 用户故事为起点 / 怎么运作 / 闭环
- [ ] `.spec/requirements-prd.md` 已更新
- [ ] 标注目录「产品需求说明PRD」已同步且正文一致
- [ ] 定稿时:第 10 章 + `autoprd-baseline.json` 已更新
- [ ] 推进至分析中/设计中/待开发时:同名任务已创建或复用,正式关联,负责人正确
- [ ] 无表结构 / 接口 / 代码路径;变更记录无样式/UI 废话
- [ ] `.spec/requirements-prd.md` + 标注目录已同步
- [ ] 定稿时:第 10 章含版本号 + `autoprd-baseline.json``prdVersion`
- [ ] 与 YunxiaoPMapp 设计完成:【交付】按**编号**回填,创建时未提前灌 MD
- [ ] 全文无 `yunxiao-requirement-lifecycle` 引导;无同名阶段任务建单
- [ ] 变更记录无样式/UI/表结构废话
## 参考
- 定稿变更日志[references/release-changelog.md](references/release-changelog.md)
- 云效阶段任务[references/yunxiao-stage-tasks.md](references/yunxiao-stage-tasks.md)
- 标注同步细则[references/annotation-sync.md](references/annotation-sync.md)
- 章节模板[references/template.md](references/template.md)
- 定稿与版本[references/release-changelog.md](references/release-changelog.md)
- 云效产品说明[references/yunxiao-description.md](references/yunxiao-description.md)
- 【交付】回填[references/yunxiao-delivery-sync.md](references/yunxiao-delivery-sync.md)
- 标注同步[references/annotation-sync.md](references/annotation-sync.md)
- 模板:[references/template.md](references/template.md)
- 故事示例:[references/granularity-example.md](references/granularity-example.md)
- 业务条线:`src/prototypes/lease-business-line-overview/lines.ts`
- 复杂判定规格:配合项目规则 `business-logic-documentation`
- 云效组合:`$yunxiao-requirement-lifecycle`(建需求时先本 Skill
- 云效组合(唯一):`$YunxiaoPMapp`
- 入库清洗:`$AutoRDO`

View File

@@ -1,12 +1,12 @@
# 功能变更记录(定稿触发)
# 功能变更记录(定稿触发)+ PRD 版本号
用户回复**需求定稿关键字**后,必须生成「自上次定稿以来」的功能变更日志,追加到 PRD **最下方**,并更新定稿基线。
用户回复**定稿关键字**后,必须生成「自上次定稿以来」的功能变更日志,追加到 PRD **最下方**按规则递增 **`prdVersion`V主.副.子)**并更新定稿基线。
## 触发关键字(命中任一)
`需求定稿` · `定稿` · `确认定稿` · `本次定稿`
`需求定稿` · `定稿` · `确认定稿` · `本次定稿` · **`本轮定稿`**
(可带模块名,如「保险采购需求定稿」。)
(可带模块名,如「保险采购本轮定稿」。可附带 `版本类型=主|副|子`
## 写什么 / 不写什么
@@ -16,44 +16,57 @@
| 变更了什么业务逻辑 / 流程 / 验收口径 | 「优化了哪些表」「改了哪些字段/接口」 |
| 用户可感知的交互结果变化 | 纯样式、动效、无语义文案微调 |
条目口吻示例:
## 版本号 `V{主}.{副}.{子}`
- 「识别失败」:失败数可点击查看失败文件与原因;仅失败时也可打开明细
- 「比价单」:审批通过后仍须在保单管理另行录入正式保单(强调不自动同步)
基线字段 `prdVersion`(无则视为 `V0.0.0`)。有功能/逻辑增量时递增;**无增量则版本号不变**。
### 判定优先级
1. **用户覆盖(优先)**
口令或对话显式指定「主 / 副 / 子」→ **以用户为准**,不再自动改判。
定稿块首行写:`判定=用户指定·主`(或副/子)。
2. **自动判定(用户未指定时)**
- **主+1**副→0子→0跨模块边界变化、主流程/状态机重做、角色权限模型大改、验收口径整体推翻等「大改动」≥1 条主导。
- **副+1**子→0能力增删改、逻辑/文案产品语义变化、故事点级功能优化(**默认多数定稿**)。
- **子+1**:仅小幅逻辑澄清;若用户明确「本轮定稿」且变更非空且未指定类型 → **至少副+1**(不用子)。
- 定稿块首行写:`判定=主:…` / `判定=副:…` / `判定=子:…`(须写依据,禁止无依据猜)。
3. **无功能增量**
版本号不变;正文写「本轮无功能/逻辑增量(仅样式或未达产品语义变更)」或「首版定稿」(无基线且首版可落到 `V1.0.0` 若视为首次发布——首版有实质内容时用主从 `V0.0.0``V1.0.0`)。
## 落点
1. **PRD 文末章节**(强制)
1. **PRD 文末章节**
`src/prototypes/<id>/.spec/requirements-prd.md``## 10. 功能变更记录`
新定稿块插在该章**最上方**(倒序:最新在上);历史块保留
新定稿块插在该章**最上方**。
2. **定稿基线**(强制)
2. **定稿基线**
`src/prototypes/<id>/.spec/autoprd-baseline.json`
```json
{
"prototypeId": "insurance-procurement",
"prdVersion": "V1.2.0",
"lastConfirmedAt": "2026-07-21T12:00:00+08:00",
"lastConfirmedLabel": "定稿 · 2026-07-21",
"lastConfirmedLabel": "定稿 · V1.2.0 · 2026-07-21",
"summaryBullets": ["…", "…"]
}
```
3. **标注目录**:同步更新「产品需求说明PRD」全文节点若有「PRD 分章」,增加或更新「功能变更记录」分章
3. **标注目录**同步「产品需求说明PRD」全文节点。
4. **云效交接**(若本轮同时走云效):把**本次定稿块**正文作为需求描述「更新内容」;旧「更新内容」挪到「更新内容·历史」
4. **云效**(若本轮走 YunxiaoPMapp按 [yunxiao-description.md](yunxiao-description.md) 更新需求产品说明;**禁止**加载 `yunxiao-requirement-lifecycle`
## 定稿工作流
1. 确认 `<prototype-id>`(从对话 / 打开文件 / 用户指名推断)
2.现有 PRD 与 `autoprd-baseline.json`(无基线则本轮视为**首版定稿**)。
3. 收集自 `lastConfirmedAt` 以来的产品语义变更
对话确认口径 → 批注/操作说明 → PRD 新旧差异 →(可选)相关提交说明。
过滤掉样式/表结构类改动
4. 若无功能增量:仍写定稿块,正文为「本轮无功能/逻辑增量(仅样式或未达产品语义变更)」或「首版定稿」
5. 追加 `### 定稿 · YYYY-MM-DD` + 条目列表到第 10 章顶部
6. 更新 `autoprd-baseline.json`;执行 annotation-sync。
7. 向用户回报基线时间、条目数、PRD 路径;若需发云效,提示可用口令。
1. 确认 `<prototype-id>`
2. 读 PRD 与 `autoprd-baseline.json`(无基线 → 首版;`prdVersion` 缺省 `V0.0.0`)。
3. 收集自 `lastConfirmedAt` 以来的产品语义变更;过滤样式/表结构。
4. 判定版本类型(用户指定优先)→ 计算新 `prdVersion`
5. 追加 `### 定稿 · V{x.y.z} · YYYY-MM-DD`(首行判定理由 + 条目)
6. 更新基线 JSONannotation-sync
7. 回报新版本号、判定理由、条目数、PRD 路径
## PRD 章节格式
@@ -62,17 +75,21 @@
> 产品经理原型发版记录。仅记功能与业务逻辑变更;不含样式/UI/表结构。
### 定稿 · 2026-07-21
### 定稿 · V1.2.0 · 2026-07-21
- 「能力名」:做了什么 / 逻辑如何变
判定=副:新增比价失败明细可点开
- 「识别失败」:失败数可点击查看失败文件与原因
-
### 定稿 · 2026-07-10
### 定稿 · V1.1.0 · 2026-07-10
判定=用户指定·副
-
```
## 与日常改原型的关系
- **改原型过程中**按 AutoPRD 主流程增量更新第 19 章;**不必**每改一次写第 10 章。
- **用户说定稿时**:才汇总写入第 10 章并刷新基线。
- **改原型过程中**:增量更新第 19 章;**不必**每改一次写第 10 章。
- **用户说定稿时**:才汇总第 10 章并刷新版本与基线。

View File

@@ -2,6 +2,22 @@
复制下列结构填写。方括号为占位。**第 4 章用户故事必须用业务条线说明口径。**
## 概要能力 → 章节映射
| 用户概要 | 本模板位置 |
|---|---|
| 总览 | §1 一句话与目标 |
| 目标 / 边界 | §12 |
| 角色 | §3 |
| 用户故事(起点→运作→闭环)/ 故事点 | §4 |
| 正逆向流程 | §5 |
| 状态 / 风险 / 关键逻辑 | §6可分小节写状态机与风险 |
| 流程图 | §7 |
| 交付 | §9 |
| 定稿变更与版本 | §10见 release-changelog |
状态与风险也可在 §6 下设 `### 状态` / `### 风险` 短节,避免另起大结构推翻存量 PRD。
```markdown
# <模块名> · 产品需求说明(全模块)
@@ -110,7 +126,9 @@ flowchart TB
> 产品经理原型发版记录。仅记功能与业务逻辑变更;不含样式/UI/表结构。
> 由「需求定稿」关键字触发追加;日常改原型不强制每改必写。详见 [release-changelog.md](release-changelog.md)。
### 定稿 · YYYY-MM-DD
### 定稿 · V{x.y.z} · YYYY-MM-DD
判定=<主|副|子|用户指定·…><一行依据>
- 「<能力名>」:<做了什么 / 逻辑如何变>
-

View File

@@ -0,0 +1,47 @@
# 【交付】任务描述回填(设计完成 · 按编号)
**`$YunxiaoPMapp`** 组合。创建【交付】时描述保持占位 `等待设计任务完成后自动填入`**本文件只在设计完成(或显式同步)时**把 AutoPRD Markdown 写入【交付】。
**禁止**按任务标题查找交付;**禁止**加载 `yunxiao-requirement-lifecycle`
## 触发时机
| 时机 | 动作 |
|---|---|
| YunxiaoPMapp **设计完成**且 AutoPRD 落盘成功 | 必须回填【交付】描述 |
| 口令 `同步交付说明:交付任务=ONEOS-xx`(或需求编号可反查交付) | 按编号回填 |
| 仅创建【交付】 / 分析中 / 设计中尚未设计完成 | **不**写 PRD 正文 |
## 前置
1. 已有【交付】任务编号:口令显式 > 需求 `## 工作项编号(系统)` > ASSOCIATED 反查校验。
2. 冲突或缺少编号 → 停下询问;禁止按 `【交付】`+标题猜。
3. 本地已有 `requirements-prd.md`(或本轮刚生成)。
## 写入内容
- 用与需求「产品说明AutoPRD」一致的正文**替换**占位文案。
- 推荐:原型链接 + `requirements-prd.md` 全文(或 YunxiaoPMapp 约定的产品说明正文)。
- 可附一句:`原始诉求见需求描述「原始诉求AutoRDO」`
- 不要删除或改写需求侧 AutoRDO 段(本步骤只改**任务**描述)。
## 执行顺序(设计完成组合)
```text
1. AutoPRD 落盘 MD + 标注同步
2. 更新需求「产品说明AutoPRD
3. 按交付任务编号 PATCH 任务描述(替换占位)
4. 附件ZIP/截图)由 YunxiaoPMapp make-export 流程负责;本文件不替代附件
5. 任一步失败 → 不得声称交付说明已更新 / 设计完成材料齐全
```
## 回报
- 交付任务编号、是否已替换占位、MD 路径
- 失败时列出缺项(无编号 / 无 MD / 写入失败)
## 负向
- 创建交付当下灌入未完成的 PRD
- 按标题 list 复用「像交付的任务」
- 引导旧 lifecycle 建同名任务

View File

@@ -0,0 +1,60 @@
# 云效需求描述:产品说明(对接 YunxiaoPMapp
发云效 / 完善需求描述时,与 **`$YunxiaoPMapp`** 双段模板对齐。
**禁止加载** `yunxiao-requirement-lifecycle`
## 需求描述固定结构(不可互相覆盖)
```markdown
## 原始诉求AutoRDO
(由 AutoRDO 清洗;设计完成也不删除;本 Skill 不覆盖本段)
## 产品说明AutoPRD
(本 Skill 写入:原型链接 + requirements-prd 正文或等价产品说明)
## 工作项编号(系统)
(由 YunxiaoPMapp 维护;本 Skill 不改本段)
```
## 产品说明段推荐拼装
```markdown
## 产品说明AutoPRD
### 原型链接
<{baseUrl}/{prototype-id}/index.html禁止加 prototypes/ 前缀;禁止去掉 index.html>
无则写「待发布」
### 需求说明
<src/prototypes/<id>/.spec/requirements-prd.md 全文原样粘贴;禁止摘要顶替>
### 更新内容
<第 10 章最新定稿块;无则「首版定稿」或「本轮无功能/逻辑增量」>
### 更新内容·历史
<旧更新内容倒序;勿删>
```
若 YunxiaoPMapp 本轮只要求「产品说明」短写:至少包含原型链接 + MD 全文或与交付回填一致的正文;**仍禁止**覆盖 AutoRDO / 工作项编号段。
## 真相源文件
1. `src/prototypes/<prototype-id>/.spec/requirements-prd.md`(主)
2. 否则 `src/resources/prd/<prototype-id>-autoprd.md`
先 Read 文件再写入;不要凭记忆重写。
## 执行步骤
1. 确认 prototype-id 与需求编号(若写云效)。
2. 读 MD 全文。
3. PATCH/更新需求描述时**只改**「产品说明AutoPRD」相关内容保留原始诉求与工作项编号。
4. 若同时设计完成:按 [yunxiao-delivery-sync.md](yunxiao-delivery-sync.md) 回填【交付】。
5. 回报需求编号、MD 路径、是否全文写入、是否已回填交付编号。
## 禁止
- 只用第 9 章摘要顶替全文(除非用户只要链接)
- 二次删减章节、去掉 mermaid/表格却声称全文已写
- 创建【交付】时灌入 PRD须等设计完成见交付回填
- 引用或配合 `yunxiao-requirement-lifecycle`

View File

@@ -1,44 +0,0 @@
# 云效阶段任务自动创建AutoPRD 负责)
本规则写在 **oneos-autoprd**,不依赖改写 `yunxiao-requirement-lifecycle`
凡本 Skill 参与的云效操作中,需求推进到下列状态时,**同一轮必须**建同名任务并正式关联需求。
## 触发状态
| 需求推进至 | 任务标签(右侧基础字段) | 负责人 | 任务标题 |
|------------|--------------------------|--------|----------|
| **分析中** | `分析` | **需求创建人**姓名 | 与需求标题**完全同名** |
| **设计中** | `设计` | **需求创建人**姓名 | 与需求标题**完全同名** |
| **待开发** | `交付`(若项目无「交付」标签则用 `开发` | **何斐** | 与需求标题**完全同名** |
## 强制字段与关系
1. **正式关联需求**:父子或关联项;只挂标题不算关联。创建后必须在界面上能看到需求 ↔ 任务关系。
2. **标签**:写入任务「标签」基础字段(见上表);标题前缀不能代替标签。
3. **创建时间沿用需求**:任务的创建时间(及标签侧可见的创建时间口径)尽量与**需求创建时间**一致。
- 平台允许改创建时间 / 用 API 指定时:写成需求的创建时间。
- 平台不允许:在任务描述首行注明 `创建时间口径=需求创建时间YYYY-MM-DD HH:mm`,并在回报里说明「平台限制未改系统创建时间」。
4. **幂等**:同一需求、同一阶段标签下,已存在**未取消**且已正式关联的同名任务 → **不新建**,只校验负责人/标签/关联是否正确,缺则补齐。
5. **顺序**:先确认需求已进入目标状态(或本轮动作将写入该状态),再创建/补齐任务;回报时给出任务编号与链接。
## 执行步骤apply 时)
```text
1. 读取需求:标题、创建人、创建时间、当前/目标状态、已关联任务列表
2. 按上表确定本轮阶段标签与负责人
3. 查重需求ID + 阶段标签 + 未取消)
4. 无则创建:标题=需求标题;标签=阶段标签;负责人=上表;创建时间口径=需求创建时间;正式关联需求
5. 有则校验并修补标签/负责人/关联
6. 回报:需求状态、任务编号、负责人、是否新建/复用
```
## 不在本规则内
- 不自动建「测试 / 发版」任务(除非用户另行要求)。
- 不因样式类 PRD 变更触发建任务;仅**需求状态**进入分析中/设计中/待开发时触发。
- 云效生命周期细则、流水线、缺陷闭环仍可由 `$yunxiao-requirement-lifecycle` 配合执行;**本建任务逻辑以 AutoPRD 本文为准**。
## 与定稿 / 需求说明的关系
- 写「需求说明 / 更新内容」仍按 AutoPRD 主流程与定稿流程。
- 推进到待开发且需要描述时:先 AutoPRD 文档,再改状态,再按本文件建任务(负责人何斐)。

View File

@@ -1,157 +0,0 @@
---
name: yunxiao-requirement-lifecycle
description: >-
Audit, design, configure, migrate, test, troubleshoot, and document Alibaba Cloud
Yunxiao/Projex requirement lifecycle automation. Use for short conversational Chinese
commands such as 记录需求、确认需求、需求定稿、开始分析、开始开发、提交测试、测试完成、
发布成功 and 验收通过; OneOS delivery or legacy stage-task model. When creating or
refreshing OneOS product requirements, first call oneos-autoprd for 需求说明 and
更新内容 (functional changelog since last 定稿), then write Yunxiao description.
Also covers role handoffs, Codeup, Testhub, pipelines, release acceptance, migration,
and Chinese runbooks without exposing credentials or changing production pipelines unexpectedly.
---
# Yunxiao Requirement Lifecycle
Use this as the single entry skill. Load only the internal modules needed for the request. Installing the skill does not change Yunxiao; live transitions start only after an authorized `apply` and verified `test` run.
## Route to modules
Read each selected file completely before acting:
| Request scope | Required module |
|---|---|
| OneOS终态模型、`【交付】`主任务、多开发子任务、迭代测试/发版、Y01Y40、A01A10、旧规则迁移 | [references/oneos-terminal-flow.md](references/oneos-terminal-flow.md) |
| Lifecycle statuses, requirement labels, related tasks, R01R12, stage entry/completion | [references/lifecycle-rules.md](references/lifecycle-rules.md) |
| Design/development/test task creation, task states, rollups, TK01TK08 | [references/task-lifecycle.md](references/task-lifecycle.md) |
| Test plans, case results, failed cases, bugs, retest, TC01TC03, DF01DF03 | [references/test-defect-closure.md](references/test-defect-closure.md) |
| Repositories, `dev`/`develop`, branches, commits, MRs, multi-repository gate, CI01 | [references/codeup-integration.md](references/codeup-integration.md) |
| test/prod pipelines, Docker callback, release changes, acceptance, CI02CI03, L01L02 | [references/pipeline-release.md](references/pipeline-release.md) |
| Live audit/apply/test, browser execution, evidence, diagnosis, rollback, governance | [references/live-operations.md](references/live-operations.md) |
| 日常口语化操作,使用“记录需求、开始分析、安排开发、提交测试、复测通过、发布成功”等短口令 | [references/simple-role-commands.md](references/simple-role-commands.md) |
| **统一运营管理平台**日常「记录需求」加速执行(已验证 ID / API / 状态三跳) | [references/oneos-pc-fast-path.md](references/oneos-pc-fast-path.md) + [assets/oneos-pc-runtime-ids.json](assets/oneos-pc-runtime-ids.json) |
| **统一运营管理平台**「记录需求到云效」完整可复制提示词A/B/C 门禁 + 30 标签) | [references/oneos-pc-record-requirement-prompt.md](references/oneos-pc-record-requirement-prompt.md) |
| 需求进入分析中/设计中/待开发时自动建同名任务、关联需求、负责人与时间沿用 | [references/auto-stage-task.md](references/auto-stage-task.md) |
| 产品、分析、设计、开发、评审、测试、缺陷、运维、验收等角色的节点沟通话术和交接回报 | [references/role-trigger-prompts.md](references/role-trigger-prompts.md) |
| Final Chinese report | [references/report-template.md](references/report-template.md) |
## 记录需求 · 参数门禁与加速(强制)
当口令为「记录需求」且项目为统一运营管理平台(含 PC 端别名)时:
1. **先读** [references/oneos-pc-fast-path.md](references/oneos-pc-fast-path.md) 与 [assets/oneos-pc-runtime-ids.json](assets/oneos-pc-runtime-ids.json),按快路径执行,禁止重复探测 create URL / 优先级 ID。
2. 若用户要求 Plan/单选优先级、推进至与标签:必须先拿到明确 **A+B+C****禁止**未选时默认「中 + 分析中」并建单。「批准计划」≠ 已选 A+B+C。完整用户口令见 [references/oneos-pc-record-requirement-prompt.md](references/oneos-pc-record-requirement-prompt.md)。
3. 优先 API 建单(创建时写入 `document`)、同名任务与打标签(`PATCH` `propertyKey=tag`);浏览器仅用于标签 API 失败或状态连跳兜底。统一运营管理平台标签从 `assets/oneos-pc-tag-catalog.md` 选择器点选,禁止按 `lines.ts` 自动映射。
## AutoPRD 组合(强制 · OneOS 产品需求)
当请求涉及**创建产品类需求、写入/刷新需求描述、快轨待开发、完善需求说明/更新内容**,或用户口令含「记录需求(带模块/原型)」「需求已经确定」「需求定稿」并要进云效时:
1. **先**加载并执行项目/全局的 **`oneos-autoprd`** skill勿跳过
2. 用其产出填充云效需求描述:
- **需求说明** ← AutoPRD 正文(产品语言;不写表结构/接口/代码)
- **更新内容** ← AutoPRD 第 10 章「功能变更记录」中自上次定稿以来的条目;无则「首版定稿」或「本轮无功能/逻辑增量」
- 已有「更新内容」时:旧段挪到 **更新内容·历史**(倒序追加,勿删)
3. 原型发版增量以 AutoPRD 功能变更记录为准PC 整包发版公告仍可另用 `AutoVUL`
4. 对象存储链接、主任务、状态推进等仍按 `oneos-terminal-flow.md` / `simple-role-commands.md`
`A02` / `A02B` 在 OneOS 项目上的默认实现方式即为调用 AutoPRD不得只写占位文案。
## 阶段同名任务(强制 · AI apply
凡将需求推进到 **分析中 / 设计中 / 待开发**(含口令「开始分析」「开始设计」「快速开发」「需求已经确定…待开发」等),必须先读并执行 [references/auto-stage-task.md](references/auto-stage-task.md)
| 状态 | 任务 | 负责人 |
|---|---|---|
| 分析中 | 与需求**同名**;标签`分析`;正式关联需求 | 需求**创建人** |
| 设计中 | 与需求**同名**;标签`设计`;正式关联需求 | 需求**创建人** |
| 待开发 | 与需求**同名**;标签`交付`(或阶段模型下`开发`);正式关联需求 | 固定**何斐** |
时间:任务计划开始(及可写的创建时间)**沿用需求**的计划开始/创建时间。查重幂等,禁止同阶段重复建单。
First identify `flow_model`:
- `stage_tasks`: use R01R12 and TK01TK08; read the five domain modules plus `live-operations.md` for a full audit.
- `oneos_delivery`: read `oneos-terminal-flow.md`, `codeup-integration.md`, `test-defect-closure.md`, `pipeline-release.md`, and `live-operations.md`.
For a narrow diagnosis, read the relevant domain module plus `live-operations.md`. Do not blend both models in one project or load unrelated modules merely because they exist.
## Classify authority
- `audit`: inspect and report only.
- `plan`: prepare a project profile and change plan only.
- `apply`: create or modify only explicitly named projects, labels, rules, and test assets.
- `test`: exercise approved rules with isolated artifacts and collect evidence.
- `document`: produce a Chinese runbook from verified facts.
Treat ambiguous requests as `audit` or `plan`. Documentation never authorizes live changes.
When the user uses a write verb defined in `simple-role-commands.md`—for example `记录需求``确认需求``开始分析``开始设计``开始开发``提交测试``复测通过``发布成功` or `验收通过`—treat it as `apply` authorization only for the current exact project and named work item. If the project is not exact, ask only for the project before writing. Query verbs such as `查状态``为什么没流转``下一步` and `给我方案` remain `audit` or `plan`.
Whenever apply changes a requirement status to `分析中``设计中` or `待开发`, also apply [references/auto-stage-task.md](references/auto-stage-task.md) in the same turn (same-name task, formal link, assignee and time rules) before reporting success.
## Build the project profile
1. Choose exactly one template and copy it outside the skill:
- `stage_tasks`: `assets/project-profile.template.json`.
- `oneos_delivery`: `assets/oneos-project-profile.template.json`.
2. Keep one independent object in `projects` for every target project; duplicate the template object when needed.
3. Replace observed statuses, rule instances, repositories, branches, pipelines, test plans, defect workflows, release evidence, and control dispositions.
4. Never add usernames, passwords, cookies, tokens, OTPs, Webhook secrets, or private keys.
5. Validate before applying:
```text
python scripts/profile_tool.py validate <profile.json>
python scripts/profile_tool.py render <profile.json> --output <execution-plan.md>
python scripts/oneos_profile_tool.py validate <oneos-profile.json>
python scripts/oneos_profile_tool.py render <oneos-profile.json> --output <execution-plan.md>
```
Do not apply while placeholders remain or validation fails.
## Completeness contract
For `stage_tasks`, account for every control for every project independently:
- `R01``R12`: requirement lifecycle and manual gates.
- `TK01``TK08`: stage-task creation, task-state transitions, requirement rollups, and idempotency.
- `TC01``TC03`: test-case execution, failed-case/defect association, and retest result update.
- `DF01``DF03`: fixed handoff, tester-pass closure, and tester-fail reopen.
- `CI01``CI03`: multi-repository coverage, callback safeguards, and environment/release separation.
- `L01``L02`: legacy immediate-close rule disposition.
Record the actual R01R12 `rule_instances`, TK01TK08 `task_rule_instances`, and all 31 `control_coverage` entries. Valid modes are `manual`, `native_rule`, `integration_bridge`, `disabled_legacy`, and `not_supported`. `not_supported` needs an owner and fallback and is never equivalent to automated.
Completeness covers the requirement lifecycle, stage-task lifecycle and rollups, Testhub closure, Codeup assets, pipeline/release evidence, and legacy-close controls. Notifications, SLA reminders, generic automatic assignment, and unrelated custom-field synchronization remain outside scope unless explicitly added to `adjunct_automations`.
For `oneos_delivery`, account for all 48 controls independently:
- `Y01``Y16`, `Y20``Y22`, `Y30``Y35`, `Y40`: native/mirrored lifecycle controls.
- `A01`, `A02`, `A02B`, `A03``A10`: AI/Webhook bridge controls.
- `TC01``TC03`, `DF01``DF03`, `CI01``CI03`, `L01``L02`: test, defect, code/release separation, and legacy-close controls.
Do not disable the old stage rules until the OneOS migration readiness gate passes: required requirement statuses exist, the main-task identity is filterable or procedurally exclusive, task workflows are ready, bridge owners and idempotency exist, and rollback evidence is saved. `L01` and `L02` remain disabled because they bypass acceptance.
## Global safety rules
- Reuse the authenticated browser session or approved semantic connector.
- Preserve unrelated rules and user edits.
- Never modify an existing production pipeline unless the user authorizes that exact change.
- Clone a test pipeline before callback experiments and modify only the clone.
- Require the expected current state in every automatic transition.
- Separate observed evidence from proposals and inference.
- Wait 530 seconds for asynchronous events and inspect execution logs.
- Stop at CAPTCHA, OTP, login approval, permission elevation, protected-branch ambiguity, or indistinguishable similarly named resources.
## Required outputs
Return only the applicable artifacts:
1. Observed inventory and current-versus-target matrix.
2. Per-project R01R12 and TK01TK08 rule-instance inventory with a 31-control ledger.
3. Live change log with reopen verification.
4. Test result per transition: `通过``异步通过``未触发``误触发` or `阻塞`.
5. Remaining risks, manual gates, and rollback steps.
6. When requested, a role-and-trigger communication playbook with copyable prompts, required evidence, next owner, and stop conditions.
7. For daily commands, answer briefly with the work item, actual state change, created/linked asset, blocker if any, and the exact next short command.

View File

@@ -1,4 +0,0 @@
interface:
display_name: "云效需求生命周期自动化"
short_description: "使用口语化短口令驱动云效需求开发测试发布闭环并自动核查"
default_prompt: "使用 $yunxiao-requirement-lifecycle把当前项目设为统一运营管理平台PC端然后通过“记录需求、开始开发、提交测试、验收通过”等短口令协作。"

View File

@@ -1,209 +0,0 @@
{
"schema_version": 2,
"verified_at": "2026-07-21",
"verified_by_example": {
"requirement_serial": "ONEOS-88",
"requirement_identifier": "a34e700286d456ee74ddc16e58",
"note": "标签 APIPATCH /workitem/workitem/{id} propertyKey=tag operateType=COVER全量标签来自 space/tag/searchspaceType=Space"
},
"project": {
"name_aliases": ["统一运营管理平台", "统一运营管理平台PC端", "统一运营管理平台 PC 端"],
"spaceIdentifier": "1280be963a5a2cc126a4118dca",
"customCode": "ONEOS",
"spaceType": "Project"
},
"people": {
"wangmian": {
"displayName": "王冕",
"identifier": "6811df000601d2fea60144a9"
},
"hefei": {
"displayName": "何斐",
"identifier": "695f0400562f09713f9c3a93"
}
},
"workitem_types": {
"product_req": {
"name": "产品类需求",
"category": "Req",
"identifier": "9uy29901re573f561d69jn40"
},
"task": {
"name": "任务",
"category": "Task",
"identifier": "ba102e46bc6a8483d9b7f25c"
}
},
"priority": {
"紧急": "646004e97f54bb77fec7b455df",
"高": "95b89e0a524d9693e1f335ffe5",
"中": "fa155d1214f9f8db222d39db3b",
"低": "92924feff9c1085891e7511872"
},
"fields": {
"plan_start": {
"fieldIdentifier": "79",
"name": "计划开始时间",
"value_shape": "epoch_ms_string_china_noon",
"example": "Date.parse('YYYY-MM-DDT12:00:00+08:00') 转 String避免 00:00 显示成前一天"
},
"plan_end": {
"fieldIdentifier": "80",
"name": "计划完成时间"
},
"tag": {
"fieldIdentifier": "tag",
"name": "标签",
"propertyKey": "tag"
}
},
"status_ui_paths": {
"from_待处理": {
"分析中": ["分析中"],
"设计中": ["设计中"],
"设计完成": ["设计完成"],
"开发中": ["设计完成", "待开发", "开发中"],
"note": "待处理下拉无「开发中」;须按路径连跳。状态 identifier 未在 UI 路径中固化,优先 UI 三跳;有可靠 API 后再补 statusIdentifier。"
}
},
"assignee_rules": {
"分析中": "creator",
"设计中": "creator",
"设计完成": "creator",
"开发中": "hefei",
"待开发": "hefei"
},
"api": {
"create_workitem": {
"url": "https://devops.aliyun.com/projex/api/workitem/workitem?_input_charset=utf-8",
"methods": ["POST", "PUT"],
"do_not_use": ["/projex/api/workitem/workitem/create"],
"required_create_fields": [
"subject",
"spaceType",
"spaceIdentifier",
"category",
"categoryIdentifier",
"workitemTypeIdentifier",
"workitemType",
"assignedTo"
],
"document_on_create": {
"supported": true,
"shape": { "content": "<html>", "formatType": "RICHTEXT" },
"note": "创建时一并写入描述,避免再开 Cangjie 编辑器"
}
},
"get_workitem": {
"url_template": "https://devops.aliyun.com/projex/api/workitem/workitem/{identifier}?_input_charset=utf-8"
},
"list_workitem": {
"url": "https://devops.aliyun.com/projex/api/workitem/workitem/list?_input_charset=utf-8",
"method": "POST"
},
"update_field_value": {
"url": "https://devops.aliyun.com/projex/api/workitem/workitem/updateWorkitemFieldValue?_input_charset=utf-8",
"method": "PATCH",
"note": "部分会话返回 InvalidWorkitem.NotFound失败则改用详情页 UI onChange / 下拉点选,勿盲目重试超过 1 次"
},
"update_document": {
"preferred": "create 时写入 document若需补写用详情页 onWorkItemEditorSubmit(html, 'RICHTEXT')",
"avoid": "对 Cangjie 编辑器直接改 DOM / 错误 onChange 形状(曾导致页面崩溃)"
},
"list_tags": {
"url": "https://devops.aliyun.com/projex/api/workspace/space/tag/search?spaceType=Space&spaceIdentifier=1280be963a5a2cc126a4118dca&q=&_input_charset=utf-8",
"method": "GET",
"note": "注意 spaceType=Space不是 Project。刷新全量标签时用此接口覆盖 tags.catalog"
},
"apply_tags": {
"url_template": "https://devops.aliyun.com/projex/api/workitem/workitem/{identifier}?_input_charset=utf-8",
"method": "PATCH",
"body_shape": {
"workitemIdentifier": "{identifier}",
"propertyKey": "tag",
"propertyValue": "{comma_separated_tag_identifiers}",
"operateType": "COVER"
},
"note": "propertyValue 为标签 identifier 逗号拼接COVER=覆盖整组。已验证于 ONEOS-88。"
}
},
"tags": {
"selection_mode": "plan_or_askquestion_selector",
"do_not_match_from": ["lease-business-line-overview/lines.ts", "业务条线说明自动推断"],
"apply_strategy": "用户从 catalog 点选标签名 → 用 identifier 调 apply_tags API失败 1 次再 UI 兜底;仍失败则停并请用户回标签名,禁止假装已打上",
"refresh_hint": "标签库变更时重新 GET list_tags 并更新本 catalog / fetched_at",
"fetched_at": "2026-07-21",
"source": "GET /projex/api/workspace/space/tag/search?spaceType=Space&spaceIdentifier=1280be963a5a2cc126a4118dca&q=",
"count": 30,
"by_name": {
"运维管理条线": "a611b2f2b7c3fd3623ba2d5f52",
"报表中心": "8428d15f45a5b34173202db758",
"能源管理": "3396ebb527358fe6f89fe42849",
"维修站管理": "e7b4da7984801e75630645f437",
"充电站管理": "6ea830485f28a0d8a6e14851a8",
"还车应结款": "4204960ce658c94b17abb7c5f6",
"交车应收款": "6e7a9127d0f70281ca65d335d9",
"加氢站管理": "6cdacae673f9e1fba96296f2ad",
"保险管理": "578ed5ba12bfcf274721e956f2",
"合同管理": "23873be81931cb0dc1bf87a456",
"租赁账单": "3e9433f571b20e80b02626d2de",
"供应商管理": "7b86b7c1f3b3da21b814c5a39d",
"客户管理": "dbf959a70bc979106dc78afa90",
"还车任务": "763de323cefee45e5270e4661e",
"安全培训": "76988b5f73ef515de5930d59b9",
"备件管理": "5d09c864767d898a4f8c0ca804",
"停车场管理": "7c522e2fb29213d7d390e78b97",
"备车管理": "22c6a3ed0e4bf95fd99bf95695",
"异动管理": "84b4333ec7c76d0fa2adcc47bf",
"调拨管理": "fa88c16c152c6fb5978e3b4339",
"上牌管理": "990af2fb716dd85568bc7019bf",
"替换车管理": "8d1decf30259b941016cadc9d2",
"还车管理": "1e0fce2d6929ff4ac13b310e97",
"交车管理": "b6947b5aca82a8c759612ba039",
"车辆管理": "cb71b6db9373d6d8c7aae452a5",
"审批中心": "338add796f2221bbc36dd77d35",
"故障管理": "ceb526a7343995577645317e9a",
"车辆年审": "5193165dad1e91a161502b54c2",
"维修管理": "f5202633870ff409e0ebc16d5f",
"工作台": "b62d21beac55c0b43389915eab"
},
"catalog": [
{ "name": "运维管理条线", "identifier": "a611b2f2b7c3fd3623ba2d5f52", "color": "#49AEAC" },
{ "name": "报表中心", "identifier": "8428d15f45a5b34173202db758", "color": "#49AEAC" },
{ "name": "能源管理", "identifier": "3396ebb527358fe6f89fe42849", "color": "#49AEAC" },
{ "name": "维修站管理", "identifier": "e7b4da7984801e75630645f437", "color": "#49AEAC" },
{ "name": "充电站管理", "identifier": "6ea830485f28a0d8a6e14851a8", "color": "#49AEAC" },
{ "name": "还车应结款", "identifier": "4204960ce658c94b17abb7c5f6", "color": "#49AEAC" },
{ "name": "交车应收款", "identifier": "6e7a9127d0f70281ca65d335d9", "color": "#49AEAC" },
{ "name": "加氢站管理", "identifier": "6cdacae673f9e1fba96296f2ad", "color": "#49AEAC" },
{ "name": "保险管理", "identifier": "578ed5ba12bfcf274721e956f2", "color": "#49AEAC" },
{ "name": "合同管理", "identifier": "23873be81931cb0dc1bf87a456", "color": "#49AEAC" },
{ "name": "租赁账单", "identifier": "3e9433f571b20e80b02626d2de", "color": "#49AEAC" },
{ "name": "供应商管理", "identifier": "7b86b7c1f3b3da21b814c5a39d", "color": "#49AEAC" },
{ "name": "客户管理", "identifier": "dbf959a70bc979106dc78afa90", "color": "#49AEAC" },
{ "name": "还车任务", "identifier": "763de323cefee45e5270e4661e", "color": "#49AEAC" },
{ "name": "安全培训", "identifier": "76988b5f73ef515de5930d59b9", "color": "#49AEAC" },
{ "name": "备件管理", "identifier": "5d09c864767d898a4f8c0ca804", "color": "#49AEAC" },
{ "name": "停车场管理", "identifier": "7c522e2fb29213d7d390e78b97", "color": "#49AEAC" },
{ "name": "备车管理", "identifier": "22c6a3ed0e4bf95fd99bf95695", "color": "#49AEAC" },
{ "name": "异动管理", "identifier": "84b4333ec7c76d0fa2adcc47bf", "color": "#49AEAC" },
{ "name": "调拨管理", "identifier": "fa88c16c152c6fb5978e3b4339", "color": "#49AEAC" },
{ "name": "上牌管理", "identifier": "990af2fb716dd85568bc7019bf", "color": "#49AEAC" },
{ "name": "替换车管理", "identifier": "8d1decf30259b941016cadc9d2", "color": "#49AEAC" },
{ "name": "还车管理", "identifier": "1e0fce2d6929ff4ac13b310e97", "color": "#49AEAC" },
{ "name": "交车管理", "identifier": "b6947b5aca82a8c759612ba039", "color": "#49AEAC" },
{ "name": "车辆管理", "identifier": "cb71b6db9373d6d8c7aae452a5", "color": "#49AEAC" },
{ "name": "审批中心", "identifier": "338add796f2221bbc36dd77d35", "color": "#49AEAC" },
{ "name": "故障管理", "identifier": "ceb526a7343995577645317e9a", "color": "#49AEAC" },
{ "name": "车辆年审", "identifier": "5193165dad1e91a161502b54c2", "color": "#49AEAC" },
{ "name": "维修管理", "identifier": "f5202633870ff409e0ebc16d5f", "color": "#49AEAC" },
{ "name": "工作台", "identifier": "b62d21beac55c0b43389915eab", "color": "#49AEAC" }
]
},
"performance_rules": {
"prefer_api_over_browser": true,
"max_endpoint_probes_per_step": 1,
"screenshot_only_at": ["after_create", "after_final_status"],
"browser_fallback_for": ["tag_apply_when_api_fails", "status_multi_hop_when_api_unknown"]
}
}

View File

@@ -1,50 +0,0 @@
# 统一运营管理平台 · 云效标签清单(选择器用)
来源:`GET /projex/api/workspace/space/tag/search?spaceType=Space&spaceIdentifier=1280be963a5a2cc126a4118dca&q=`
抓取时间2026-07-21
机器可读:同目录 `oneos-pc-runtime-ids.json``tags`
## 使用约定
- **记录需求**时标签由用户用选择器点选(`AskQuestion` / Plan ○),**不要**再按 `lines.ts` 业务条线说明自动推断。
- Agent 用点选到的 `name``tags.by_name``identifier`,再 `PATCH` 打标。
- 完整建单提示词(含 A/B/C 与 30 标签枚举):[references/oneos-pc-record-requirement-prompt.md](../references/oneos-pc-record-requirement-prompt.md)
## 全量标签30
| # | 标签名 | identifier |
|---|---|---|
| 1 | 运维管理条线 | `a611b2f2b7c3fd3623ba2d5f52` |
| 2 | 报表中心 | `8428d15f45a5b34173202db758` |
| 3 | 能源管理 | `3396ebb527358fe6f89fe42849` |
| 4 | 维修站管理 | `e7b4da7984801e75630645f437` |
| 5 | 充电站管理 | `6ea830485f28a0d8a6e14851a8` |
| 6 | 还车应结款 | `4204960ce658c94b17abb7c5f6` |
| 7 | 交车应收款 | `6e7a9127d0f70281ca65d335d9` |
| 8 | 加氢站管理 | `6cdacae673f9e1fba96296f2ad` |
| 9 | 保险管理 | `578ed5ba12bfcf274721e956f2` |
| 10 | 合同管理 | `23873be81931cb0dc1bf87a456` |
| 11 | 租赁账单 | `3e9433f571b20e80b02626d2de` |
| 12 | 供应商管理 | `7b86b7c1f3b3da21b814c5a39d` |
| 13 | 客户管理 | `dbf959a70bc979106dc78afa90` |
| 14 | 还车任务 | `763de323cefee45e5270e4661e` |
| 15 | 安全培训 | `76988b5f73ef515de5930d59b9` |
| 16 | 备件管理 | `5d09c864767d898a4f8c0ca804` |
| 17 | 停车场管理 | `7c522e2fb29213d7d390e78b97` |
| 18 | 备车管理 | `22c6a3ed0e4bf95fd99bf95695` |
| 19 | 异动管理 | `84b4333ec7c76d0fa2adcc47bf` |
| 20 | 调拨管理 | `fa88c16c152c6fb5978e3b4339` |
| 21 | 上牌管理 | `990af2fb716dd85568bc7019bf` |
| 22 | 替换车管理 | `8d1decf30259b941016cadc9d2` |
| 23 | 还车管理 | `1e0fce2d6929ff4ac13b310e97` |
| 24 | 交车管理 | `b6947b5aca82a8c759612ba039` |
| 25 | 车辆管理 | `cb71b6db9373d6d8c7aae452a5` |
| 26 | 审批中心 | `338add796f2221bbc36dd77d35` |
| 27 | 故障管理 | `ceb526a7343995577645317e9a` |
| 28 | 车辆年审 | `5193165dad1e91a161502b54c2` |
| 29 | 维修管理 | `f5202633870ff409e0ebc16d5f` |
| 30 | 工作台 | `b62d21beac55c0b43389915eab` |
## 选择器文案C 段)
已并入 [oneos-pc-record-requirement-prompt.md](../references/oneos-pc-record-requirement-prompt.md)「用户口令」;此处仅作 identifier 对照表。

View File

@@ -1,119 +0,0 @@
{
"schema_version": 1,
"flow_model": "oneos_delivery",
"organization": "请填写组织名称",
"work_item_type": "产品类需求",
"target_lifecycle": [
"待处理", "已确认", "分析中", "分析完成", "设计中", "设计完成",
"待开发", "开发中", "开发完成", "待测试", "测试中", "测试完成",
"发布中", "发布完成", "发布失败", "已关闭"
],
"task_labels": ["交付", "开发", "测试", "发版"],
"policies": {
"require_formal_relations": true,
"require_current_state_condition": true,
"allow_automatic_final_close_without_acceptance": false,
"require_nonzero_development_tasks": true,
"test_success_is_production_release": false,
"bridge_idempotency_key_components": ["项目ID", "需求ID", "动作类型"],
"require_signed_timestamped_replay_protected_callbacks": true
},
"projects": [
{
"name": "请填写项目名称",
"migration_phase": "P0",
"requirement_statuses_observed": ["请填写当前全部需求状态"],
"task_workflow_mode": "B",
"task_identity_mode": "task_label",
"native_rule_can_filter_related_task_identity": false,
"main_task_prefix": "【交付】",
"development_task_prefix": "【开发】",
"test_task_prefix": "【测试】",
"release_task_prefix": "【发版】",
"repositories": [
{
"name": "请填写仓库名称",
"role": "frontend",
"integration_branch": "develop",
"codeup_integrated": true,
"required_for_mr_gate": true,
"evidence": "请填写观察证据"
}
],
"test_plan": {
"name": "请填写测试计划名称",
"iteration_formally_related": true,
"cases_partitioned_by_requirement": true,
"fixed_defect_is_terminal": false,
"tester_retest_required": true,
"evidence": "请填写观察证据"
},
"release": {
"release_task_formally_related_to_iteration": true,
"production_evidence_separate_from_test": true,
"acceptance_required_after_release": true,
"production_pipeline_unchanged": true,
"evidence": "请填写观察证据"
},
"legacy_rules": [
{
"name": "请填写旧规则显示名",
"disposition": "keep_until_ready",
"enabled": true,
"reason": "请填写保留、停用或替换原因",
"evidence": "请填写观察证据"
}
],
"controls": [
{"id":"Y01","mode":"not_supported","enabled":false,"owner":"请填写负责人","fallback":"桥接创建并关联唯一主任务","evidence":"请填写观察证据"},
{"id":"Y02","mode":"not_supported","enabled":false,"owner":"请填写负责人","fallback":"桥接或人工同步分析完成","evidence":"请填写观察证据"},
{"id":"Y03","mode":"not_supported","enabled":false,"owner":"请填写负责人","fallback":"桥接或人工同步设计中","evidence":"请填写观察证据"},
{"id":"Y04","mode":"not_supported","enabled":false,"owner":"请填写负责人","fallback":"桥接或人工同步设计完成","evidence":"请填写观察证据"},
{"id":"Y05","mode":"not_supported","enabled":false,"owner":"请填写负责人","fallback":"桥接或人工同步待开发","evidence":"请填写观察证据"},
{"id":"Y06","mode":"not_supported","enabled":false,"owner":"请填写负责人","fallback":"桥接或人工同步开发中","evidence":"请填写观察证据"},
{"id":"Y07","mode":"not_supported","enabled":false,"owner":"请填写负责人","fallback":"桥接或人工同步开发完成","evidence":"请填写观察证据"},
{"id":"Y08","mode":"not_supported","enabled":false,"owner":"请填写负责人","fallback":"桥接或人工同步待测试","evidence":"请填写观察证据"},
{"id":"Y09","mode":"not_supported","enabled":false,"owner":"请填写负责人","fallback":"桥接或人工同步测试中","evidence":"请填写观察证据"},
{"id":"Y10","mode":"not_supported","enabled":false,"owner":"请填写测试负责人","fallback":"测试负责人按用例和缺陷闭环同步测试完成","evidence":"请填写观察证据"},
{"id":"Y11","mode":"not_supported","enabled":false,"owner":"请填写发布负责人","fallback":"发版任务提交后人工同步发布中","evidence":"请填写观察证据"},
{"id":"Y12","mode":"not_supported","enabled":false,"owner":"请填写发布负责人","fallback":"核对生产发布证据后人工同步发布完成","evidence":"请填写观察证据"},
{"id":"Y13","mode":"not_supported","enabled":false,"owner":"请填写发布负责人","fallback":"人工记录发布失败及原因","evidence":"请填写观察证据"},
{"id":"Y14","mode":"manual","enabled":true,"owner":"请填写产品负责人","fallback":"产品验收后人工关闭","evidence":"请填写观察证据"},
{"id":"Y15","mode":"not_supported","enabled":false,"owner":"请填写项目管理员","fallback":"只保留一个权威镜像方向","evidence":"请填写观察证据"},
{"id":"Y16","mode":"not_supported","enabled":false,"owner":"请填写产品负责人","fallback":"快轨时桥接同步主任务","evidence":"请填写观察证据"},
{"id":"Y20","mode":"native_rule","enabled":true,"owner":"请填写研发负责人","fallback":"开发负责人人工开始任务和需求","evidence":"请填写观察证据"},
{"id":"Y21","mode":"integration_bridge","enabled":false,"owner":"请填写研发负责人","fallback":"人工核对全部开发任务和MR","evidence":"请填写观察证据"},
{"id":"Y22","mode":"integration_bridge","enabled":false,"owner":"请填写项目管理员","fallback":"人工创建并关联唯一测试任务","evidence":"请填写观察证据"},
{"id":"Y30","mode":"integration_bridge","enabled":false,"owner":"请填写测试负责人","fallback":"人工同步待测试","evidence":"请填写观察证据"},
{"id":"Y31","mode":"manual","enabled":true,"owner":"请填写测试负责人","fallback":"测试负责人开始测试","evidence":"请填写观察证据"},
{"id":"Y32","mode":"integration_bridge","enabled":false,"owner":"请填写测试负责人","fallback":"按需求用例包人工验收","evidence":"请填写观察证据"},
{"id":"Y33","mode":"integration_bridge","enabled":false,"owner":"请填写发布负责人","fallback":"人工提交发版任务并同步范围","evidence":"请填写观察证据"},
{"id":"Y34","mode":"integration_bridge","enabled":false,"owner":"请填写流水线负责人","fallback":"人工核对生产发布成功","evidence":"请填写观察证据"},
{"id":"Y35","mode":"integration_bridge","enabled":false,"owner":"请填写流水线负责人","fallback":"人工记录生产发布失败","evidence":"请填写观察证据"},
{"id":"Y40","mode":"manual","enabled":true,"owner":"请填写产品负责人","fallback":"人工关联迭代","evidence":"请填写观察证据"},
{"id":"A01","mode":"not_supported","enabled":false,"owner":"请填写产品负责人","fallback":"人工上传并回写链接","evidence":"请填写观察证据"},
{"id":"A02","mode":"not_supported","enabled":false,"owner":"请填写产品负责人","fallback":"人工维护更新内容历史","evidence":"请填写观察证据"},
{"id":"A02B","mode":"not_supported","enabled":false,"owner":"请填写产品负责人","fallback":"人工维护需求说明","evidence":"请填写观察证据"},
{"id":"A03","mode":"integration_bridge","enabled":false,"owner":"请填写项目管理员","fallback":"人工建需求和唯一主任务","evidence":"请填写观察证据"},
{"id":"A04","mode":"integration_bridge","enabled":false,"owner":"请填写研发负责人","fallback":"人工拆分开发任务","evidence":"请填写观察证据"},
{"id":"A05","mode":"integration_bridge","enabled":false,"owner":"请填写研发负责人","fallback":"人工核对MR并完成开发任务","evidence":"请填写观察证据"},
{"id":"A06","mode":"integration_bridge","enabled":false,"owner":"请填写项目管理员","fallback":"人工建唯一测试任务","evidence":"请填写观察证据"},
{"id":"A07","mode":"integration_bridge","enabled":false,"owner":"请填写测试负责人","fallback":"人工核对用例与缺陷闭环","evidence":"请填写观察证据"},
{"id":"A08","mode":"integration_bridge","enabled":false,"owner":"请填写发布负责人","fallback":"人工建发版任务和更新说明","evidence":"请填写观察证据"},
{"id":"A09","mode":"integration_bridge","enabled":false,"owner":"请填写流水线负责人","fallback":"人工回写发布成败","evidence":"请填写观察证据"},
{"id":"A10","mode":"manual","enabled":true,"owner":"请填写产品负责人","fallback":"产品验收后人工关闭","evidence":"请填写观察证据"},
{"id":"TC01","mode":"manual","enabled":true,"owner":"请填写测试负责人","fallback":"逐条执行并记录用例结果","evidence":"请填写观察证据"},
{"id":"TC02","mode":"manual","enabled":true,"owner":"请填写测试负责人","fallback":"人工正式关联失败用例和缺陷","evidence":"请填写观察证据"},
{"id":"TC03","mode":"manual","enabled":true,"owner":"请填写测试负责人","fallback":"复测后更新原用例状态","evidence":"请填写观察证据"},
{"id":"DF01","mode":"manual","enabled":true,"owner":"请填写测试负责人","fallback":"已修复继续等待复测","evidence":"请填写观察证据"},
{"id":"DF02","mode":"manual","enabled":true,"owner":"请填写测试负责人","fallback":"复测通过后关闭缺陷并通过用例","evidence":"请填写观察证据"},
{"id":"DF03","mode":"manual","enabled":true,"owner":"请填写测试负责人","fallback":"复测失败后重开缺陷并保持用例失败","evidence":"请填写观察证据"},
{"id":"CI01","mode":"manual","enabled":true,"owner":"请填写研发负责人","fallback":"人工核对全部前后端MR","evidence":"请填写观察证据"},
{"id":"CI02","mode":"not_supported","enabled":false,"owner":"请填写流水线负责人","fallback":"使用test副本评审回调POC","evidence":"请填写观察证据"},
{"id":"CI03","mode":"manual","enabled":true,"owner":"请填写发布负责人","fallback":"人工区分test、生产发布和验收","evidence":"请填写观察证据"},
{"id":"L01","mode":"disabled_legacy","enabled":false,"owner":"请填写项目管理员","fallback":"保持发布完成等待验收","evidence":"请填写观察证据"},
{"id":"L02","mode":"disabled_legacy","enabled":false,"owner":"请填写项目管理员","fallback":"保持发布完成等待验收","evidence":"请填写观察证据"}
]
}
]
}

View File

@@ -1,148 +0,0 @@
{
"schema_version": 3,
"organization": "请填写组织名称",
"work_item_type": "产品类需求",
"lifecycle": [
"待处理",
"已确认",
"分析中",
"分析完成",
"设计中",
"设计完成",
"待开发",
"开发中",
"开发完成",
"测试中",
"测试完成",
"完成发布",
"已完成"
],
"requirement_labels": ["分析", "设计", "开发", "测试"],
"automation_policy": {
"require_current_state_condition": true,
"inspect_rule_order_and_cascades": true,
"allow_automatic_final_close_without_acceptance": false,
"zero_related_items_are_complete": false,
"development_start_event_candidates": ["添加关联分支", "正式关联代码资产"],
"require_code_assets_linked_to_requirement_and_development_task": true,
"stage_task_creation_idempotency_key_components": ["项目ID", "需求ID", "阶段类型"]
},
"test_closure_policy": {
"accepted_case_states": ["已通过"],
"rejected_case_states": ["未执行", "待测试", "阻塞", "未通过"],
"defect_fixed_is_terminal": false,
"require_tester_retest": true
},
"projects": [
{
"name": "请填写项目名称",
"work_item_type": "产品类需求",
"release_status": "完成发布",
"final_status": "已完成",
"labels_observed": ["分析", "设计", "开发", "测试"],
"repositories": [
{
"name": "请填写仓库名称",
"role": "frontend",
"integration_branch": "dev",
"codeup_integrated": true,
"required_for_mr_gate": true,
"evidence": "请填写仓库与需求正式关联的观察证据"
}
],
"test_pipeline": {
"name": "请填写test流水线名称",
"environment": "test",
"is_clone_for_callback_poc": true,
"original_pipeline_unchanged": true,
"docker_success_callback_enabled": false,
"callback_security": {
"signed": false,
"timestamp_checked": false,
"replay_protected": false,
"idempotent_by_execution_id": false,
"failure_retry_tested": false
},
"evidence": "请填写流水线观察证据"
},
"release_evidence": {
"mode": "native_release_change",
"target_environment": "请填写目标发布环境",
"test_success_is_production_release": false,
"evidence": "请填写发布证据"
},
"test_plan": {
"name": "请填写测试计划名称",
"requirement_formally_related": true,
"case_states_observed": ["未执行", "已通过", "未通过", "阻塞"],
"evidence": "请填写测试计划与用例状态证据"
},
"defect_workflow": {
"fixed_status": "已修复",
"fixed_is_terminal": false,
"tester_retest_required": true,
"closed_status": "请填写缺陷真实关闭状态",
"reopen_status": "请填写缺陷复测失败后的状态",
"evidence": "请填写缺陷工作流证据"
},
"rule_instances": [
{"id": "R01", "mode": "manual", "actual_rule_name": "人工门禁:需求确认", "trigger": "负责人确认", "source_status": "待处理", "target_status": "已确认", "conditions": ["范围、负责人和验收口径明确"], "action": "人工变更状态为已确认", "order": 1, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R02", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "添加关联任务工作项", "source_status": "已确认", "target_status": "分析中", "conditions": ["当前状态=已确认", "需求自身标签包含分析"], "action": "变更状态为分析中", "order": 2, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R03", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "关联任务工作项状态变化", "source_status": "分析中", "target_status": "分析完成", "conditions": ["当前状态=分析中", "本阶段分析任务全部完成;若平台不能过滤阶段则记录替代策略"], "action": "变更状态为分析完成", "order": 3, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R04", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "添加关联任务工作项", "source_status": "分析完成", "target_status": "设计中", "conditions": ["当前状态=分析完成", "需求自身标签包含设计"], "action": "变更状态为设计中", "order": 4, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R05", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "关联任务工作项状态变化", "source_status": "设计中", "target_status": "设计完成", "conditions": ["当前状态=设计中", "本阶段设计任务全部完成;若平台不能过滤阶段则记录替代策略"], "action": "变更状态为设计完成", "order": 5, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R06", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "添加关联任务工作项", "source_status": "设计完成", "target_status": "待开发", "conditions": ["当前状态=设计完成", "需求自身标签包含开发"], "action": "变更状态为待开发", "order": 6, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R07", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "添加关联分支或正式关联代码资产", "source_status": "待开发", "target_status": "开发中", "conditions": ["当前状态=待开发", "仓库已集成", "代码资产正式关联需求"], "action": "变更状态为开发中", "order": 7, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R08", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "关联合并请求状态变化", "source_status": "开发中", "target_status": "开发完成", "conditions": ["当前状态=开发中", "全部相关前后端合并请求已合并"], "action": "变更状态为开发完成", "order": 8, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R09", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "添加关联任务工作项", "source_status": "开发完成", "target_status": "测试中", "conditions": ["当前状态=开发完成", "需求自身标签包含测试"], "action": "变更状态为测试中", "order": 9, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R10", "mode": "manual", "actual_rule_name": "人工门禁:测试验收", "trigger": "测试验收任务完成或获批回调", "source_status": "测试中", "target_status": "测试完成", "conditions": ["当前状态=测试中", "范围内用例全部通过", "失败用例已复测通过", "范围内缺陷已由测试复测并关闭"], "action": "变更状态为测试完成", "order": 10, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R11", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "关联发布变更完成或获批回调", "source_status": "测试完成", "target_status": "完成发布", "conditions": ["当前状态=测试完成", "目标环境发布证据满足组织口径"], "action": "变更状态为完成发布", "order": 11, "enabled": false, "has_current_state_condition": true, "evidence": "请填写观察证据"},
{"id": "R12", "mode": "manual", "actual_rule_name": "人工门禁:业务验收", "trigger": "业务验收", "source_status": "完成发布", "target_status": "已完成", "conditions": ["当前状态=完成发布", "正式验收证据有效"], "action": "人工变更状态为已完成", "order": 12, "enabled": true, "has_current_state_condition": true, "evidence": "请填写观察证据"}
],
"task_rule_instances": [
{"id": "TK01", "mode": "manual", "actual_rule_name": "人工门禁:设计任务真实开工", "trigger": "负责人开始处理设计任务", "scope": "设计任务", "source_state": "待处理", "conditions": ["任务标签=设计", "任务正式关联需求"], "actions": ["设计任务变为处理中"], "order": 101, "enabled": true, "evidence": "请填写观察证据"},
{"id": "TK02", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "设计任务状态变为已完成", "scope": "产品需求", "source_state": "设计中", "conditions": ["本阶段设计任务非零且全部完成"], "actions": ["需求变为设计完成"], "order": 102, "enabled": true, "evidence": "请填写观察证据"},
{"id": "TK03", "mode": "integration_bridge", "actual_rule_name": "桥接:设计完成后创建开发任务", "trigger": "需求状态变为设计完成", "scope": "产品需求", "source_state": "设计完成", "conditions": ["不存在同需求同阶段未取消开发任务", "幂等键=项目ID+需求ID+开发"], "actions": ["创建并关联开发任务", "开发任务标签=开发", "开发任务状态=待处理"], "order": 103, "enabled": false, "evidence": "请填写观察证据"},
{"id": "TK04", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "开发任务创建并正式关联需求", "scope": "产品需求", "source_state": "设计完成", "conditions": ["需求标签包含开发", "开发任务关系可见"], "actions": ["需求变为待开发"], "order": 104, "enabled": true, "evidence": "请填写观察证据"},
{"id": "TK05", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "添加正式关联分支或代码资产", "scope": "产品需求和开发任务", "source_state": "需求=待开发;开发任务=待处理", "conditions": ["代码资产同时关联需求和开发任务", "仓库已接入项目"], "actions": ["需求变为开发中", "开发任务变为处理中"], "order": 105, "enabled": true, "evidence": "请填写观察证据"},
{"id": "TK06", "mode": "native_rule", "actual_rule_name": "请填写云效规则显示名", "trigger": "关联合并请求状态变化", "scope": "产品需求和开发任务", "source_state": "需求=开发中;开发任务=处理中", "conditions": ["全部相关前后端MR已合并到真实dev/develop", "MR同时关联需求和开发任务"], "actions": ["需求变为开发完成", "开发任务变为已完成"], "order": 106, "enabled": true, "evidence": "请填写观察证据"},
{"id": "TK07", "mode": "integration_bridge", "actual_rule_name": "桥接test部署成功后创建测试任务", "trigger": "test流水线部署成功", "scope": "产品需求", "source_state": "开发完成", "conditions": ["流水线执行ID未处理", "不存在同需求同阶段未取消测试任务", "回调签名和防重放验证通过"], "actions": ["创建并关联测试任务", "测试任务变为处理中", "关联测试计划和用例", "需求变为测试中"], "order": 107, "enabled": false, "evidence": "请填写观察证据"},
{"id": "TK08", "mode": "manual", "actual_rule_name": "人工门禁:测试任务验收闭环", "trigger": "测试验收完成", "scope": "产品需求和测试任务", "source_state": "需求=测试中;测试任务=处理中", "conditions": ["用例全部通过", "失败用例已复测", "范围内缺陷已由测试关闭"], "actions": ["测试任务变为已完成", "需求变为测试完成"], "order": 108, "enabled": true, "evidence": "请填写观察证据"}
],
"control_coverage": [
{"id": "R01", "mode": "manual", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写负责人", "fallback": "人工确认需求范围与验收口径"},
{"id": "R02", "mode": "native_rule", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写负责人", "fallback": "人工进入分析中"},
{"id": "R03", "mode": "native_rule", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写负责人", "fallback": "人工核对本阶段分析任务"},
{"id": "R04", "mode": "native_rule", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写负责人", "fallback": "人工进入设计中"},
{"id": "R05", "mode": "native_rule", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写负责人", "fallback": "人工核对本阶段设计任务"},
{"id": "R06", "mode": "native_rule", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写负责人", "fallback": "人工进入待开发"},
{"id": "R07", "mode": "native_rule", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写负责人", "fallback": "开发人员真实开工时人工开始开发"},
{"id": "R08", "mode": "native_rule", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写负责人", "fallback": "人工核对全部相关MR"},
{"id": "R09", "mode": "native_rule", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写负责人", "fallback": "人工进入测试中"},
{"id": "R10", "mode": "manual", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写测试负责人", "fallback": "测试负责人验收任务"},
{"id": "R11", "mode": "native_rule", "enabled": false, "evidence": "请填写观察证据", "owner": "请填写发布负责人", "fallback": "人工核对发布变更"},
{"id": "R12", "mode": "manual", "enabled": true, "evidence": "请填写观察证据", "owner": "请填写产品负责人", "fallback": "产品或业务负责人验收"},
{"id": "TK01", "mode": "manual", "enabled": true, "evidence": "请填写设计任务开工证据", "owner": "请填写设计负责人", "fallback": "负责人真实开工时人工改为处理中"},
{"id": "TK02", "mode": "native_rule", "enabled": true, "evidence": "请填写设计任务完成汇总证据", "owner": "请填写产品负责人", "fallback": "人工核对非零设计任务全部完成"},
{"id": "TK03", "mode": "integration_bridge", "enabled": false, "evidence": "请填写自动创建开发任务能力证据", "owner": "请填写项目管理员", "fallback": "从需求中人工新建并关联唯一开发任务"},
{"id": "TK04", "mode": "native_rule", "enabled": true, "evidence": "请填写开发任务关联证据", "owner": "请填写项目管理员", "fallback": "人工核对关系后将需求改为待开发"},
{"id": "TK05", "mode": "native_rule", "enabled": true, "evidence": "请填写需求和开发任务双对象开工证据", "owner": "请填写研发负责人", "fallback": "开发人员真实开工时人工更新任务和需求"},
{"id": "TK06", "mode": "native_rule", "enabled": true, "evidence": "请填写需求和开发任务双对象完成证据", "owner": "请填写研发负责人", "fallback": "人工核对全部相关MR后完成任务和需求"},
{"id": "TK07", "mode": "integration_bridge", "enabled": false, "evidence": "请填写test部署回调和自动创建测试任务证据", "owner": "请填写流水线负责人", "fallback": "test部署成功后人工创建并关联测试任务"},
{"id": "TK08", "mode": "manual", "enabled": true, "evidence": "请填写测试任务与需求双闭环证据", "owner": "请填写测试负责人", "fallback": "测试负责人验收后同步完成测试任务和需求"},
{"id": "TC01", "mode": "manual", "enabled": true, "evidence": "请填写用例执行状态证据", "owner": "请填写测试负责人", "fallback": "逐条执行并记录用例结果"},
{"id": "TC02", "mode": "manual", "enabled": true, "evidence": "请填写失败用例关联缺陷证据", "owner": "请填写测试负责人", "fallback": "人工核对失败用例与缺陷正式关系"},
{"id": "TC03", "mode": "manual", "enabled": true, "evidence": "请填写用例复测更新证据", "owner": "请填写测试负责人", "fallback": "复测后更新原用例状态"},
{"id": "DF01", "mode": "manual", "enabled": true, "evidence": "请填写已修复交接证据", "owner": "请填写测试负责人", "fallback": "已修复继续等待测试复测"},
{"id": "DF02", "mode": "manual", "enabled": true, "evidence": "请填写复测通过关闭证据", "owner": "请填写测试负责人", "fallback": "测试复测通过后关闭缺陷"},
{"id": "DF03", "mode": "manual", "enabled": true, "evidence": "请填写复测失败重开证据", "owner": "请填写测试负责人", "fallback": "测试复测失败后重开缺陷"},
{"id": "CI01", "mode": "native_rule", "enabled": true, "evidence": "请填写多仓库关联证据", "owner": "请填写研发负责人", "fallback": "人工核对全部前后端MR"},
{"id": "CI02", "mode": "not_supported", "enabled": false, "evidence": "请填写流水线能力证据", "owner": "请填写流水线负责人", "fallback": "复制test流水线后评审回调POC"},
{"id": "CI03", "mode": "manual", "enabled": true, "evidence": "请填写环境与发布证据", "owner": "请填写发布负责人", "fallback": "人工区分test部署、生产发布与业务验收"},
{"id": "L01", "mode": "disabled_legacy", "enabled": false, "evidence": "请填写旧规则盘点证据", "owner": "请填写项目管理员", "fallback": "使用独立业务验收任务"},
{"id": "L02", "mode": "disabled_legacy", "enabled": false, "evidence": "请填写旧规则盘点证据", "owner": "请填写项目管理员", "fallback": "保持发布完成状态等待业务验收"}
],
"adjunct_automations": []
}
]
}

View File

@@ -1,62 +0,0 @@
# 需求进阶段自动建同名任务(强制 · AI 桥接)
当**产品类需求**推进到下列状态时AI`apply`)必须查重后创建/复用**与需求同名**的任务,并**正式关联**该需求。不得只改需求状态却不建任务。
## 触发状态与字段规则
| 需求进入状态 | 任务标题 | 任务标签(右侧基础字段) | 负责人 | 时间字段 |
|---|---|---|---|---|
| **分析中** | = 需求标题(同名) | `分析` | **需求创建人**姓名 | 沿用需求(见下) |
| **设计中** | = 需求标题(同名) | `设计` | **需求创建人**姓名 | 沿用需求(见下) |
| **待开发** | = 需求标题(同名) | `交付`OneOS 主任务);若项目仍用阶段开发标签则用 `开发` | 固定 **何斐** | 沿用需求(见下) |
### 时间沿用(「标签创建时间沿用需求的」)
按平台能力尽量对齐,优先级:
1. 任务 **计划开始时间** = 需求的计划开始时间;若需求无计划开始,则用需求 **创建时间** 的日期。
2. 若平台允许写入任务创建时间:任务创建时间 = 需求创建时间。
3. 若都不能改创建时间:仍写计划开始;并在任务描述首行注明:`创建时间沿用需求YYYY-MM-DD HH:mm`
### 正式关联(强制)
- 使用云效**父子项或关联项**把任务挂到**该产品需求**。
- 仅标题写需求编号、或只关联其他任务而不关联需求 → **不合格**,必须补关联后再回报成功。
- 标题前缀(如 `【分析】`**不是**关联;本规则默认标题与需求**完全同名**;若项目强制标题前缀,允许 `【分析】{需求标题}`,但仍须正式关联 + 正确标签。
## 幂等与查重
幂等键:
```text
项目ID + 需求ID + 阶段标签(分析|设计|交付/开发)
```
执行顺序:
1. 查询该需求下是否已有**未取消**、同阶段标签、同名(或同名前缀)任务。
2. **已存在一条** → 复用:核对正式关联、标签、负责人(待开发须为何斐)、时间字段;缺则补齐;**不新建第二条**。
3. **存在多条冲突** → 停止创建,列出任务编号,请人合并后再继续。
4. **不存在** → 创建并正式关联,再改需求状态(若口令是「推进到某状态」且任务尚未建好,先建任务再改状态,避免有状态无任务)。
快轨直接到 **待开发**(跳过分析/设计):只建/复用 **待开发** 那一条同名任务(负责人何斐),不要为跳过的阶段补建分析/设计任务,除非用户明确要求。
## 与 OneOS 终态模型对齐
- `oneos_delivery`:待开发阶段的同名任务即唯一 **【交付】主任务**(标题优先与需求同名;标签=`交付`)。分析中/设计中另建同名阶段任务(标签分析/设计),**不**再额外建第二条交付主任务。
- `stage_tasks`:分析/设计/开发阶段任务按上表;待开发对应标签=`开发` 的同名任务,负责人何斐(若项目配置了其他默认开发负责人,以用户当次口令为准,口令未写则何斐)。
## AI 回报模板(短)
```text
需求ONEOSP-xxx「标题」→ 状态:分析中/设计中/待开发
任务TASK-xxx「同名」标签负责人计划开始已正式关联需求
查重:新建 / 复用
```
## 负向(不得误做)
- 需求仅到 `已确认` / `待处理`:不自动建分析/设计/待开发任务。
- 不得把样式类口头变更当成建任务触发。
- 不得在未查重时重复创建同阶段同名任务。
- 不得把负责人设错:分析中/设计中≠何斐(除非创建人就是何斐);待开发必须何斐(除非用户当次明确改派)。

View File

@@ -1,60 +0,0 @@
# Codeup研发资产集成
## 目录
1. 仓库覆盖
2. 分支策略
3. 正式关联
4. 提交与合并请求
5. CI01多仓库门禁
6. 验证场景
## 1. 仓库覆盖
前端、后端均可触发研发自动化,前提是仓库接入正确项目,分支/提交/MR正式关联需求规则没有错误限定到单一仓库。
逐仓库记录仓库名、角色、项目集成状态、Webhook、实际集成分支、是否纳入全部MR门禁和观察证据。
## 2. 分支策略
- 检查真实集成分支:存在`dev`则优先`dev`,否则使用存在的`develop`
- 从集成分支创建`feature/<WORK-ITEM-ID>``fix/<WORK-ITEM-ID>`
- 一个需求涉及多个仓库时,每个仓库可有一个同名活动分支。
- 快速迭代仍使用短生命周期分支;合并后是否删除按仓库策略和用户授权处理。
- 不直接推送保护分支,不为自动化方便创建不存在的`dev`/`develop`
## 3. 正式关联
关联优先级:
1. 从需求“代码”区域创建分支并回到需求确认资产数量。
2. 在Codeup创建分支/MR时显式选择工作项存在开发任务时同时关联需求和开发任务。
3. 使用以工作项ID结尾的分支名并在需求页确认自动关联。
4. 提交说明关键字仅作兜底,必须回需求页验证。
需求编号、分支名或MR标题有关键字不等同已正式关联。
## 4. 提交与合并请求
- 提交可带工作项ID增强追溯但不判定开发完成。
- MR目标必须是仓库真实集成分支。
- MR显式关联需求和对应开发任务并完成评审。
- 只有全部相关MR合并后才观察R08。
- 首次提交时间不作为真实开发开始时间;人工“开始开发”为效能主口径。
## 5. CI01多仓库门禁
CI01要求所有相关前后端仓库的分支、提交和MR都正式关联需求与对应开发任务。只遗漏一个仓库或只关联需求平台的“全部MR已合并”就可能只看到部分资产、提前完成需求或完全无法完成开发任务。
如果无法可靠聚合所有仓库保留人工核对门禁不能声称R08已完全自动化。
## 6. 验证场景
| 场景 | 操作 | 期望 |
|---|---|---|
| 正式关联分支 | 从需求代码区创建真实仓库分支 | 异步进入开发中 |
| 非关联分支 | 仅本地创建/推送无关系分支 | 不触发R07 |
| 仅有提交 | 提交代码但不合并MR | 不进入开发完成 |
| 单仓库MR | 所有相关仓库只有一个MR合并 | 仍保持开发中 |
| 多仓库全部合并 | 所有相关MR正式关联并合并 | 进入开发完成 |
| 错误集成分支 | MR指向非真实集成分支 | 阻塞并修正,不伪造通过 |

View File

@@ -1,103 +0,0 @@
# 需求生命周期与项目规则
## 目录
1. 状态参数化
2. R01R12规则矩阵
3. 阶段入口和阶段完成
4. 开发开始与开发完成
5. 标签、任务和关键字
6. 规则实例与限制
## 1. 状态参数化
典型流程为:
```text
待处理 → 已确认 → 分析中 → 分析完成 → 设计中 → 设计完成 → 待开发
→ 开发中 → 开发完成 → 测试中 → 测试完成 → 完成发布/发布完成 → 已完成/已关闭
```
逐项目读取真实状态。`完成发布``发布完成``已完成``已关闭`是候选映射,不能静默互换或创建近义重复状态。
## 2. R01R12规则矩阵
| ID | 流转 | 触发事件 | 必要条件 | 动作 | 方式 |
|---|---|---|---|---|---|
| R01 | 待处理 → 已确认 | 负责人确认 | 范围、负责人、优先级、验收口径明确 | 改为已确认 | 人工 |
| R02 | 已确认 → 分析中 | 添加关联任务工作项 | 当前状态;需求自身标签包含`分析` | 改为分析中 | 原生规则 |
| R03 | 分析中 → 分析完成 | 关联任务状态变化 | 当前状态;本阶段分析任务全部完成 | 改为分析完成 | 原生/条件化 |
| R04 | 分析完成 → 设计中 | 添加关联任务工作项 | 当前状态;需求自身标签包含`设计` | 改为设计中 | 原生规则 |
| R05 | 设计中 → 设计完成 | 关联任务状态变化 | 当前状态;本阶段设计任务全部完成 | 改为设计完成 | 原生/条件化 |
| R06 | 设计完成 → 待开发 | 添加关联任务工作项 | 当前状态;需求自身标签包含`开发` | 改为待开发 | 原生规则 |
| R07 | 待开发 → 开发中 | 添加关联分支或正式关联代码资产 | 当前状态;仓库已集成;资产正式关联 | 改为开发中 | 自动兜底 |
| R08 | 开发中 → 开发完成 | 关联合并请求状态变化 | 当前状态全部相关MR已合并 | 改为开发完成 | 原生规则 |
| R09 | 开发完成 → 测试中 | 添加关联任务工作项 | 当前状态;需求自身标签包含`测试` | 改为测试中 | 原生规则 |
| R10 | 测试中 → 测试完成 | 测试验收任务或获批回调 | 当前状态;用例、失败复测、缺陷均闭环 | 改为测试完成 | 人工/桥接 |
| R11 | 测试完成 → 发布完成状态 | 发布变更完成或获批回调 | 当前状态;目标环境发布证据有效 | 改为真实发布状态 | 原生/桥接 |
| R12 | 发布完成状态 → 项目终态 | 业务验收 | 当前状态;验收证据有效 | 改为真实终态 | 默认人工 |
R05R10与阶段任务自身状态的双向联动见`task-lifecycle.md`R10的用例和缺陷口径见`test-defect-closure.md`R11、R12见`pipeline-release.md`R07、R08的代码资产口径见`codeup-integration.md`
## 3. 阶段入口和阶段完成
R02、R04、R06、R09同时要求
1. 从需求中“新建并关联”或“关联已有”任务工作项。
2. 当前状态等于前一阶段完成状态。
3. 需求自身包含目标阶段标签。
如果规则编辑器不能读取需求自身标签,标签只能用于筛选和报表;保留人工入口或使用当前状态+显式关联事件,不能声称标签已成为技术门槛。
R03、R05首选“本阶段任务全部完成”。若平台只能判断“全部关联任务工作项”选择一种明确策略
- 阶段开始时才创建/关联本阶段任务。
- 使用不同工作项类型,并确认规则能按类型过滤。
- 使用父子需求拆分阶段。
- 保留人工完成动作。
不得把零个关联任务当作全部完成。使用关联项状态变化触发,并执行零关联项负向测试。
## 4. 开发开始与开发完成
R07采用双轨口径
- 效能主口径:开发人员真实开工时执行“开始开发”。
- 自动兜底:创建或正式关联需求分支/代码资产后进入`开发中`
首次提交可能晚于真实开工,不能作为权威开始时间。自动规则必须要求当前状态=`待开发`
R08推荐定义
```text
事件 = 关联合并请求状态变化
且当前状态 = 开发中
且全部相关合并请求 = 已合并
则状态 = 开发完成
```
提交活动不能证明开发完成。全部相关前端、后端MR都必须正式关联并合并到实际集成分支。
## 5. 标签、任务和关键字
`分析``设计``开发``测试`标签加在产品类需求自身。
“添加关联任务工作项”依赖云效正式关系,不依赖标题关键字。有效方式:
- 在需求详情新建并关联任务。
- 在需求详情关联已有任务。
- 在任务详情选择该需求为父项/关联项,并在页面确认关系。
仅写需求编号、粘贴链接或添加同名标签都不能替代正式关联。编号仍建议出现在标题中,方便检索和审计。
## 6. 规则实例与限制
每个项目分别记录R01R12的实际规则显示名/人工门禁、精确触发、源状态、目标状态、全部条件、动作、顺序、启用状态、执行账号和证据。
已知限制:
- 规则通常异步执行530秒内不要过早判失败。
- “全部关联项”只能看到已集成并正式关联的资产。
- 提前创建未来阶段任务可能阻塞“全部任务完成”。
- 需求状态规则不会自动更新阶段任务状态必须同时配置TK01TK08。
- 平台能力因模板、版本和权限不同以当前UI和执行日志为准。

View File

@@ -1,133 +0,0 @@
# 线上实施、验证与治理
## 目录
1. 安全边界
2. 项目盘点
3. 规则应用
4. 隔离验证
5. 故障诊断
6. 回滚
7. 运行治理
## 1. 安全边界
- 只操作明确授权的组织、项目、工作项类型和测试资产。
- 复用已登录会话不记录账号、密码、Cookie、Token、OTP、私钥或签名材料。
- 不修改现有prod流水线回调实验只改test副本。
- 不删除测试需求、分支、MR、流水线或规则除非另有授权。
- 保留无关规则和用户修改。
## 2. 项目盘点
先记录`flow_model=stage_tasks``flow_model=oneos_delivery`。发现两套规则同时启用时判定为迁移中,不按规则名称猜测主模型。
对每个项目独立记录:
| 类别 | 必查内容 |
|---|---|
| 项目 | 精确项目名、项目ID、工作项类型 |
| 工作流 | 全部状态、顺序、发布状态、终态 |
| 阶段任务 | 设计/开发/测试任务类型、状态、标签、父子/关联关系、自动创建能力 |
| 标签 | `分析``设计``开发``测试` |
| 规则 | 名称、事件、条件、动作、顺序、启用、执行账号、后继规则 |
| Codeup | 前后端仓库、集成、Webhook、真实`dev/develop` |
| 流水线 | test/prod名称、环境、部署阶段、副本能力 |
| 发布 | 发布变更关系、目标环境、完成状态 |
| 测试 | 计划范围、用例状态枚举、需求关系 |
| 缺陷 | 已修复、复测、关闭态、重开态、权限 |
两个项目只复制逻辑不复制内部ID、仓库、分支、流水线、规则ID或观察证据。
OneOS终态迁移还要盘点`待测试/发布中/发布失败`状态缺口、主任务身份方式、任务工作流方案A/B、原生规则能否过滤关联任务身份、Y/A控制负责人和幂等键。门禁未齐时保留可用旧规则只停用会绕过验收或造成已确认误触发的规则。
## 3. 规则应用
1. 导出或截图现有规则和启用状态。
2. 识别后继规则和可能的连锁路径。
3. 创建缺失阶段标签。
4. 一次只创建或修改一条规则。
5. 设置精确触发、当前状态、需求标签、其他条件和目标动作。
6. 保存后重新打开,核对全部字段、顺序、启用状态和执行账号。
7. 把真实字段写回该项目`rule_instances`
8. 触发最小事件等待530秒。
9. 查看状态、研发资产、执行日志和二次流转。
10. 记录证据后再处理下一条。
手工推进只能标记为“测试准备动作”,不能伪造规则通过。
## 4. 隔离验证
测试需求命名示例:
```text
[自动化测试] 产品类需求生命周期验证-YYYYMMDD
```
| 用例 | 操作 | 期望 | 负向检查 |
|---|---|---|---|
| T01 | 已确认+分析标签+关联任务 | 分析中 | 无标签不流转 |
| T02 | 完成分析任务 | 分析完成 | 零任务不误触发 |
| T03 | 设计标签+关联任务 | 设计中 | 仅标题关键字不触发 |
| T04 | 完成设计任务 | 设计完成 | 未完成任务阻塞 |
| T04a | 设计完成后触发TK03 | 创建且只创建一个开发任务 | 重复事件不得重复创建 |
| T04b | 开发任务正式关联需求 | 需求待开发、任务待处理 | 仅标题编号不触发 |
| T05 | 开发标签+关联任务 | 待开发 | 错误当前状态不触发 |
| T06 | 正式关联真实仓库分支 | 开发中 | 非关联分支不触发 |
| T06a | 同一代码资产同时关联需求和开发任务 | 需求开发中、开发任务处理中 | 只关联需求不得声称任务已联动 |
| T07 | 前后端各关联MR只合并一个 | 保持开发中 | 不得提前完成 |
| T08 | 全部相关MR合并 | 开发完成 | 仅提交不得完成 |
| T08a | 全部相关MR同时关联开发任务并合并 | 开发任务已完成 | 部分仓库MR未合并时阻塞 |
| T09 | 测试标签+关联测试任务 | 测试中 | 未来任务不应误阻塞 |
| T09a | test流水线部署成功触发TK07 | 创建且只创建一个测试任务并进入处理中 | 流水线失败或重复回调不得创建 |
| T10a | 执行全部用例并记录结果 | 每条有明确状态 | 未执行/阻塞/失败阻塞 |
| T10b | 失败用例关联缺陷,改为已修复 | 保持测试中 | 未复测不得完成 |
| T10c | 复测通过/失败 | 关闭并通过/重开并失败 | 用例缺陷状态一致 |
| T11 | 发布变更完成/获批回调 | 发布完成状态 | 重复回调不重复推进 |
| T12a | 进入发布完成后等待异步窗口 | 停留发布完成 | L01/L02不得误关闭 |
| T12b | 完成正式业务验收 | 项目终态 | test或发布不能替代验收 |
结果只使用:`通过``异步通过``未触发``误触发``阻塞`
## 5. 故障诊断
按顺序检查:
1. 事件是否真实发生,而不是只有相似标题/标签。
2. 当前状态是否精确匹配。
3. 标签是否加在需求自身。
4. 任务、分支、MR、发布变更是否正式关联。
5. 仓库是否接入正确项目Webhook是否有效。
6. 全部相关MR是否合并到真实集成分支。
7. 规则是否启用,执行账号是否有权限。
8. 执行日志是未匹配、失败还是排队。
9. 用例是否仍有未执行、阻塞或失败。
10. 缺陷是否仅到已修复,尚未复测关闭。
11. 目标状态是否触发后继/重复规则。
12. 是否发生`测试完成 → 发布完成 → 终态`瞬时连锁。
13. 是否等待合理异步窗口。
14. 是否误用另一个项目的内部ID或证据。
15. 缺陷与原用例在复测后的状态是否一致。
16. 需求状态变化是否遗漏对应阶段任务状态,或任务变化是否遗漏需求汇总。
17. 自动创建下一阶段任务是否具有需求ID+阶段类型幂等门禁。
18. 项目是否混用R/TK阶段模型与Y/A终态模型。
19. OneOS主任务是否唯一且可被规则可靠识别。
20. 是否缺少`待测试``发布中``发布失败`或重试流转边。
## 6. 回滚
- 先禁用本次新增规则,再恢复修改前条件和动作。
- 保留变更前截图/导出和规则ID。
- 回调POC通过禁用副本回滚删除需单独授权。
- 分支/MR等测试资产按仓库策略清理删除需单独授权。
- 不覆盖与本次变更无关的规则。
## 7. 运行治理
- 每季度复核规则账号、权限、启用状态和失败日志。
- 新增仓库时同步验证项目集成、Webhook和多仓库门禁。
- 状态、标签或工作项类型重命名后逐条复核依赖规则。
- 保护`master/main`和真实`dev/develop`
- 监控超过7天无活动的需求分支未经授权不删除。
- 分开统计自动流转时间与真实业务开始时间。
- 持续检查回调签名、时间戳、防重放、幂等和失败重试。

View File

@@ -1,117 +0,0 @@
# 统一运营管理平台 · 记录需求快路径
真相源运行时 ID[assets/oneos-pc-runtime-ids.json](../assets/oneos-pc-runtime-ids.json)
验证样例ONEOS-84「测试需求」2026-07-21
**用户可复制完整口令A/B/C 门禁 + 30 标签):** [oneos-pc-record-requirement-prompt.md](oneos-pc-record-requirement-prompt.md)
本文件只服务**日常 `记录需求` apply**。全量审计/规则配置仍读 `live-operations.md` 等模块。
## 0. 执行门禁(强制)
用户口令要求 Plan / 单选「优先级」「推进至」「标签」时:
1. **必须**先拿到明确的 A紧急/高/中/低、B分析中/设计中/设计完成/开发中)、**C标签可多选**
2. 标签 **C** 只能从 [assets/oneos-pc-tag-catalog.md](../assets/oneos-pc-tag-catalog.md) / `tags.catalog` 点选;**禁止**按 `lines.ts` 或业务条线说明自动推断。
3. 来源优先:`AskQuestion` 点选 → Plan 批准时写明的 A+B+C → 用户一句话点明。
4. **禁止**:未选时默认「中 + 分析中」并继续建单;**禁止**未选标签时自作主张打标。
5. 「批准/Implement 计划」≠ 已选 A+B+C计划正文若仍是空 ○,必须先问清再执行。
多条需求名称时:每条或整批共用的优先级/推进至/标签仍须用户点选后再写云效。
## 1. 加载配方(禁止重探)
对项目别名含「统一运营管理平台」时:
1. 读取 `assets/oneos-pc-runtime-ids.json`
2. **禁止**再探测 create URL不要用 `/workitem/create`)。
3. **禁止**对优先级 ID 做猜测重试超过配方表。
## 2. 标准执行顺序(目标 13 分钟)
```text
AutoPRD → API 建需求(含描述) → API 建阶段任务 → API 打标签(COVER) → 状态连跳 → 一次校验回报
```
### 2.1 AutoPRD
- 先跑 `$oneos-autoprd`(模块/原型来自口令或对话页)。
- 描述 HTML 最小块:`【原型】` + `【目标】` + `【非目标】` + `【更新内容】`(无变更记录则「首版定稿」)。
### 2.2 API 建产品类需求
`POST`(失败再试一次 `PUT`
`https://devops.aliyun.com/projex/api/workitem/workitem?_input_charset=utf-8`
要点:
- `workitemTypeIdentifier` **与** `workitemType` 都设为产品类需求 ID。
- `document: { content: html, formatType: 'RICHTEXT' }` 创建时写入。
- `fieldValueList``priority``assignedTo`、可选 `79`(计划开始,中国时区中午 epoch 字符串)。
- 开发中:需求负责人用何斐 ID分析中/设计中/设计完成:创建人 ID。
### 2.3 API 建同名阶段任务
同一 create 接口,`category=Task``parentIdentifier=需求ID`,标题与需求**完全同名**。
| 推进至 | 任务标签目标 | 负责人 |
|---|---|---|
| 分析中 | 分析 | 创建人 |
| 设计中 | 设计 | 创建人 |
| 开发中 / 待开发 | 开发或交付 | 何斐 |
查重:同需求 + 同阶段标签 + 未取消 → 复用,不建第二条。详见 [auto-stage-task.md](auto-stage-task.md)。
### 2.4 状态连跳(开发中)
从「待处理」到「开发中」UI 固定路径:
```text
待处理 → 设计完成 → 待开发 → 开发中
```
每跳点开状态按钮选目标;不要在「待处理」下拉里找「开发中」(没有)。
其它推进至:
- 分析中 / 设计中 / 设计完成:待处理下拉通常可直达。
### 2.5 标签(选择器点选 + API
1. 用户已从 `tags.catalog` 点选标签名(见门禁 C`tags.by_name` 得到 identifier。
2. **优先 API**(已验证):
```http
PATCH https://devops.aliyun.com/projex/api/workitem/workitem/{identifier}?_input_charset=utf-8
Content-Type: application/json
{
"workitemIdentifier": "{identifier}",
"propertyKey": "tag",
"propertyValue": "{id1,id2}",
"operateType": "COVER"
}
```
3. API 失败 1 次 → UI 标签选择器勾选 → **确定**;仍失败 → **停止并请用户回复标签名**,禁止报「已打上」。
4. **禁止**对照 `lines.ts` / 业务条线说明自动映射;刷新全量标签:`GET` `api.list_tags``spaceType=Space`)。
### 2.6 校验与回报(只做一次)
核对:编号、链接、状态、优先级、负责人、计划开始、描述含原型、任务父项、标签。
截图最多:建单后、终态后各一次。
## 3. 性能红线
| 允许 | 禁止 |
|---|---|
| 配方内 ID / URL | 每步 3+ 端点盲探 |
| create 带描述 | 默认先开富文本再粘贴 |
| 状态固定三跳 | React fiber 乱调 onChange易白屏 |
| 标签失败问用户 | 标签失败仍声称成功 |
| API 失败 1 次改 UI | 同失败 payload 循环重试 |
## 4. 浏览器会话
- 复用已登录 `devops.aliyun.com`;不记录 Cookie/Token。
- 优先已打开的「统一运营管理平台」项目页;锁 tab 后执行,结束解锁。

View File

@@ -1,139 +0,0 @@
# 统一运营管理平台 · 记录需求到云效(完整提示词)
复制下方「用户口令」整段发给 AgentAgent 须先弹出 Plan / 单选卡让你点选 **A 优先级 + B 推进至 + C 标签****未点选前不得建单**。
---
## 用户口令(复制整段)
```text
使用 $yunxiao-requirement-lifecycle + $oneos-autoprd
记录需求到云效 · 统一运营管理平台
【需求名】
(填写 1 条或多条,例:车辆资产功能优化)
【描述来源】
$oneos-autoprd原型/模块填写oneos-h5-vehicle-assets
【已锁定】
- 项目:统一运营管理平台
- 计划开始:今日
- 负责人:分析中 / 设计中 / 设计完成 → 创建人;开发中 → 何斐
【请你先 Plan 点选,未选完禁止写云效】
A. 优先级(单选)
○ 紧急
○ 高
○ 中
○ 低
B. 推进至(单选)
○ 分析中(建同名「分析」任务,负责人=创建人)
○ 设计中(建同名「设计」任务,负责人=创建人)
○ 设计完成(只改状态,负责人=创建人;不强制建阶段任务)
○ 开发中(建同名开发/交付任务,负责人=何斐;状态连跳:待处理→设计完成→待开发→开发中)
C. 标签(可多选;只能从下列 30 个云效标签中选,禁止自造、禁止按业务条线/lines.ts 自动推断)
○ 运维管理条线
○ 报表中心
○ 能源管理
○ 维修站管理
○ 充电站管理
○ 还车应结款
○ 交车应收款
○ 加氢站管理
○ 保险管理
○ 合同管理
○ 租赁账单
○ 供应商管理
○ 客户管理
○ 还车任务
○ 安全培训
○ 备件管理
○ 停车场管理
○ 备车管理
○ 异动管理
○ 调拨管理
○ 上牌管理
○ 替换车管理
○ 还车管理
○ 交车管理
○ 车辆管理
○ 审批中心
○ 故障管理
○ 车辆年审
○ 维修管理
○ 工作台
【我确认 A+B+C 后你再执行】
批准 / Implement 计划时,我会写明所选值,例如:
优先级:高;推进至:设计完成;标签:运维管理条线
【执行要求Agent
1. 读快路径references/oneos-pc-fast-path.md + assets/oneos-pc-runtime-ids.json
2. 先 $oneos-autoprd 生成描述(【原型】【目标】【非目标】【更新内容】;无增量则「首版定稿」)
3. API 建产品类需求POST /workitem/workitem创建时写入 document
4. 计划开始=今日;按 B 推进状态;按规则建/复用同名阶段任务
5. 标签:用 tags.by_name 查 identifierPATCH propertyKey=tag operateType=COVERAPI 失败 1 次再 UI 兜底
6. 一次校验回报:编号、链接、状态、优先级、负责人、计划开始、标签、描述、阶段任务
7. 禁止默认「中+分析中」;禁止未选标签时自作主张打标;标签失败不得报「已成功」
```
---
## 单条需求示例(填好即用)
```text
使用 $yunxiao-requirement-lifecycle + $oneos-autoprd
记录需求到云效 · 统一运营管理平台
【需求名】
测试需求3
【描述来源】
$oneos-autoprd原型/模块oneos-h5-vehicle-assets
【已锁定】
- 项目:统一运营管理平台
- 计划开始:今日
- 负责人:分析中/设计中/设计完成=创建人;开发中=何斐
请先 Plan 让我点选 A 优先级、B 推进至、C 标签30 项 catalog禁止 lines.ts 推断)。
我确认后再执行快路径建单。
```
确认回复示例:
```text
优先级:高;推进至:设计完成;标签:运维管理条线
```
---
## Agent 执行清单(内部,勿省略)
| 步 | 动作 |
|---|---|
| 0 | 门禁A+B+C 已明确Implement ≠ 已选 |
| 1 | `$oneos-autoprd` → HTML 描述 |
| 2 | `POST …/workitem/workitem` 建需求 + document |
| 3 | 字段priority、assignedTo、79=今日 |
| 4 | 若 B∈{分析中,设计中,开发中} → 同名阶段任务(查重复用) |
| 5 | 状态推进至 B开发中三跳 |
| 6 | `PATCH …/workitem/{id}` 打标签 COVER |
| 7 | 回报 ONEOS-xxx + 链接 + 核对表 |
标签 API 形态:
```json
{
"workitemIdentifier": "{id}",
"propertyKey": "tag",
"propertyValue": "{identifier1},{identifier2}",
"operateType": "COVER"
}
```
参考:`assets/oneos-pc-tag-catalog.md``assets/oneos-pc-runtime-ids.json``tags.by_name`

View File

@@ -1,192 +0,0 @@
# OneOS终态交付模型与迁移规则
## 目录
1. 模型选择与边界
2. 工作项和状态
3. 原生Y规则
4. AI与Webhook桥接
5. 迁移就绪门禁
6. 分阶段实施
7. 验收与负向测试
8. 已知风险和回滚
## 1. 模型选择与边界
OneOS终态模型以需求为阶段看板唯一真相
```text
迭代
├─ 多个产品类需求
├─ 按需求分包的测试计划
└─ 一条【发版】任务
产品类需求
└─ 一条【交付】主任务
├─ 多条【开发】任务
└─ 一条【测试】任务
```
每个项目只能选择一个主模型:
- `stage_tasks`分析、设计、开发、测试各建阶段任务使用R/TK控制。
- `oneos_delivery`一条交付主任务镜像需求多开发任务汇总使用Y/A控制。
不得同时启用两套进场规则。若项目仍有分析/设计标签驱动的R规则先记录为`legacy_active`,完成迁移就绪检查后再停用。
## 2. 工作项和状态
### 2.1 任务身份
| 任务 | 数量 | 必须关系 | 识别优先级 |
|---|---:|---|---|
| `【交付】`主任务 | 每需求1条 | 正式关联需求 | 独立工作项类型 > 任务标签`交付` > 标题前缀流程约束 |
| `【开发】`任务 | 每需求1..N条 | 正式关联需求和主任务 | 独立类型 > 标签`开发` > 标题前缀 |
| `【测试】`任务 | 每需求1条 | 正式关联需求和主任务 | 独立类型 > 标签`测试` > 标题前缀 |
| `【发版】`任务 | 每迭代1条 | 正式关联迭代和本批需求 | 独立类型 > 标签`发版` > 标题前缀 |
标题关键字本身不构成正式关系。规则编辑器不能读取关联任务的类型、标签或标题时,不得声称原生规则能区分主任务和开发任务;使用桥接或人工门禁。
### 2.2 需求状态
目标状态顺序:
```text
待处理 → 已确认 → 分析中 → 分析完成 → 设计中 → 设计完成
→ 待开发 → 开发中 → 开发完成 → 待测试 → 测试中 → 测试完成
→ 发布中 → 发布完成 / 发布失败 → 已关闭
```
允许的快轨至少包括`已确认 → 待开发``设计完成 → 待开发``发布失败 → 发布中`用于重试。已有近义状态先映射,禁止静默创建`完成发布/发布完成``已完成/已关闭`等重复状态。
### 2.3 任务状态
- 主任务:首选与需求同名镜像状态。
- 开发任务:`待处理 → 处理中 → 已完成`,另有取消态。
- 测试任务:`待处理/待测试 → 测试中 → 已完成`
- 发版任务:`待处理 → 发布中 → 发布完成/发布失败`
若任务工作流不能承载主任务全量状态不配置Y02Y16原生镜像由桥接更新需求并记录主任务显示口径。
## 3. 原生Y规则
统一规则前缀:`[OneOS终态] Yxx ...`。保存后重新打开核对事件、条件、动作、顺序、启用状态和执行账号。
### 3.1 主任务镜像
| ID | 触发 | 条件 | 动作 | 默认方式 |
|---|---|---|---|---|
| Y01 | 新增正式关联主任务 | 主任务可可靠识别;需求为待处理/已确认 | 需求与主任务进入分析中或获批快轨 | 原生/桥接 |
| Y02 | 主任务到分析完成 | 正式关联唯一需求 | 需求到分析完成 | 原生 |
| Y03 | 主任务到设计中 | 正式关联唯一需求 | 需求到设计中 | 原生 |
| Y04 | 主任务到设计完成 | 正式关联唯一需求 | 需求到设计完成 | 原生 |
| Y05 | 主任务到待开发 | 正式关联唯一需求 | 需求到待开发;负责人按项目配置 | 原生/桥接 |
| Y06 | 主任务到开发中 | 正式关联唯一需求 | 需求到开发中 | 原生 |
| Y07 | 主任务到开发完成 | 正式关联唯一需求 | 需求到开发完成 | 原生 |
| Y08 | 主任务到待测试 | 正式关联唯一需求 | 需求到待测试 | 原生 |
| Y09 | 主任务到测试中 | 正式关联唯一需求 | 需求到测试中 | 原生 |
| Y10 | 主任务到测试完成 | Testhub门禁通过 | 需求到测试完成 | 桥接优先 |
| Y11 | 主任务到发布中 | 发版任务和迭代范围有效 | 需求到发布中 | 原生/桥接 |
| Y12 | 主任务到发布完成 | 生产发布证据有效 | 需求到发布完成 | 桥接 |
| Y13 | 主任务到发布失败 | 生产发布失败证据有效 | 需求到发布失败并记录原因 | 桥接 |
| Y14 | 主任务到已关闭 | 产品验收证据有效 | 需求到已关闭 | 默认人工 |
| Y15 | 需求状态变化 | 存在唯一主任务且无循环风险 | 主任务同名镜像 | 可选原生 |
| Y16 | 需求快轨到待开发 | 存在唯一主任务 | 主任务到待开发 | 原生/桥接 |
每条双向镜像规则必须有防循环条件。平台无法区分“由本规则写入”的事件时,只保留一个权威方向。
### 3.2 开发任务汇总
| ID | 触发 | 条件 | 动作 | 默认方式 |
|---|---|---|---|---|
| Y20 | 新增第一条开发任务或正式关联开发分支 | 需求=待开发开发任务数量≥1任务已指派 | 需求和主任务到开发中;对应开发任务处理中 | 原生/桥接 |
| Y21 | 开发任务完成 | 非取消开发任务数量≥1且全部完成全部相关MR已合并 | 需求和主任务到开发完成 | 桥接优先 |
| Y22 | 开发完成 | 同需求无未取消测试任务;幂等键未处理 | 创建并关联唯一测试任务,进入待测试 | 桥接 |
现有的“任务添加分支且标签=开发待处理→处理中”和“全部MR已合并且标签=开发处理中→已完成”可作为Y20/Y21的任务侧子规则保留。需求侧“全部MR已合并”只能看到正式关联资产必须执行多仓库负向测试。
### 3.3 测试、发布和迭代
| ID | 触发 | 条件 | 动作 | 默认方式 |
|---|---|---|---|---|
| Y30 | 创建测试任务 | 正式关联需求和主任务 | 需求/主任务到待测试 | 桥接 |
| Y31 | 首条用例执行或测试负责人开工 | 测试任务=待处理/待测试 | 测试任务、需求、主任务到测试中 | 原生/人工 |
| Y32 | 测试验收完成 | 本需求用例包全部通过且缺陷闭环 | 三个对象完成测试阶段 | 桥接/人工 |
| Y33 | 发版任务提交 | 发版任务正式关联迭代与本批需求 | 发版任务和本批需求到发布中 | 原生/桥接 |
| Y34 | 生产发布成功 | 流水线执行、环境、范围、签名和幂等均有效 | 到发布完成 | 桥接 |
| Y35 | 生产发布失败 | 同上;失败证据有效 | 到发布失败并记录原因 | 桥接 |
| Y40 | 需求到待开发 | 未关联迭代 | 通知产品负责人,不自动写入未知迭代 | 通知/人工 |
test部署只能允许测试开始不能触发Y34。发布完成后必须停留等待产品/业务验收;禁止自动进入已关闭。
## 4. AI与Webhook桥接
| ID | 能力 | 最小门禁 |
|---|---|---|
| A01 | 发布原型/附件并回写需求描述 | 外部存储授权;链接可审计 |
| A02 | 生成并保留更新内容历史 | 不覆盖历史段;**OneOS 默认调用 `$oneos-autoprd` 第 10 章「功能变更记录」(自上次定稿以来);旧段挪到「更新内容·历史」** |
| A02B | 生成产品可读需求说明 | 不写实现机密;保留来源;**OneOS 默认调用 `$oneos-autoprd` 全文/交付口径写入「需求说明」** |
| A03 | 建需求和唯一主任务并快轨待开发 | 幂等查询;正式关系可见;**建单写描述前先完成 A02+A02BAutoPRD**;进入待开发时按 [auto-stage-task.md](auto-stage-task.md) 建/复用与需求同名任务,负责人何斐,时间沿用需求 |
| A03B | 需求进入分析中/设计中自动建同名阶段任务 | 标签分析/设计;负责人=需求创建人;正式关联;时间沿用需求;与 A03 同一套查重 |
| A04 | 拆分多条开发任务 | 负责人、范围和父子关系明确 |
| A05 | 按MR证据关闭开发任务 | 所有仓库、目标分支和关联关系完整 |
| A06 | 全部开发完成后建唯一测试任务 | 幂等键=`项目ID+需求ID+create_test_task` |
| A07 | 按Testhub结果完成测试 | 用例与缺陷口径满足TC/DF控制 |
| A08 | 按迭代创建发版任务和更新说明 | 正式关联迭代和本批需求 |
| A09 | 发布成败回写 | 验证环境、签名、时间戳、执行ID和范围 |
| A10 | 产品验收后关闭 | 明确验收人和证据;不得由发布成功替代 |
所有桥接必须具备最小权限服务账号、签名、时间戳、防重放、幂等、失败重试、审计日志和人工回退。不得把未部署的AI能力写成已自动化。
## 5. 迁移就绪门禁
只有全部满足时才停用旧R/TK进场规则
1. 需求状态已包含`待测试``发布中``发布失败`,并配置必要流转边。
2. 主任务能被可靠识别;若只能靠标题前缀,已明确由桥接处理,不使用无过滤原生镜像。
3. 主任务和开发/测试/发版任务的工作流已选定并验证。
4. Y/A控制逐项指定`native_rule``integration_bridge``manual``not_supported`
5. A03、A06、A08、A09具备幂等键、负责人和回退方案。
6. Codeup前后端仓库、真实`dev/develop`、正式关联和多仓库MR门禁已验证。
7. Testhub按需求分包未执行、阻塞、失败用例和仅“已修复”缺陷会阻塞测试完成。
8. test、生产发布、发布变更和产品验收证据已分离。
9. 已保存旧规则名称、条件、顺序、启用状态和执行账号证据。
10. `L01``L02`已停用,发布完成不会瞬时关闭。
未通过门禁时:保留当前可用规则,只停用会绕过验收或造成误触发的规则,并输出迁移计划。
## 6. 分阶段实施
- P0补齐工作流、唯一主任务、快轨待开发、负责人和旧规则备份。
- P1开发任务拆分、分支/MR双关联、多仓库完成门禁、唯一测试任务。
- P2迭代、Testhub按需求分包、用例和缺陷复测闭环。
- P3发版任务、生产流水线成败回写、发布失败重试、产品验收关闭。
每阶段先在隔离测试需求验证,再启用下一阶段。新规则不补触发历史事件;历史数据修正必须单独记录。
## 7. 验收与负向测试
| ID | 操作 | 期望 | 负向检查 |
|---|---|---|---|
| V01 | 创建需求和唯一主任务 | 正式关联且不重复 | 重放不得建第二条主任务 |
| V02 | 未建开发任务 | 保持待开发 | 主任务本身不得被当作开发任务 |
| V03 | 建两条开发任务 | 进入开发中 | 无正式关系或无负责人不触发 |
| V04 | 只完成一条开发任务/MR | 保持开发中 | 不得提前完成 |
| V05 | 所有开发任务和MR完成 | 开发完成并只建一条测试任务 | 重复回调不重复创建 |
| V06 | 同迭代其他需求未测完 | 本需求仍可独立完成测试 | 不按整个计划全绿判断 |
| V07 | 用例失败且缺陷仅已修复 | 保持测试中 | 未复测不得完成 |
| V08 | 复测通过/失败 | 用例通过+缺陷关闭 / 用例失败+缺陷重开 | 双方状态必须一致 |
| V09 | test部署成功 | 允许测试开始 | 不得发布完成 |
| V10 | 生产发布成功 | 发布完成并停留 | 不得自动已关闭 |
| V11 | 生产发布失败后重试 | 发布失败→发布中 | 原因和执行ID可审计 |
| V12 | 产品验收 | 已关闭 | 无验收证据不关闭 |
## 8. 已知风险和回滚
- “全部关联任务完成”若无法按任务身份过滤,会把主任务或测试任务纳入,默认交桥接。
- 仅标题前缀不能替代正式关系,也不能保证原生规则可过滤。
- 需求和主任务双向镜像可能循环,只保留一个权威方向或增加来源防重。
- 分支/MR只关联需求而未关联开发任务会导致任务状态不更新。
- 发布完成自动关闭会绕过产品验收;`L01``L02`默认停用。
回滚顺序先禁用本次新增Y/A入口恢复旧规则启用状态和顺序再恢复状态流转边保留已创建任务、关系和执行日志删除任何资产需单独授权。

View File

@@ -1,66 +0,0 @@
# 流水线、发布与最终验收
## 目录
1. 环境证据边界
2. R11发布完成
3. CI02回调POC
4. CI03证据分离
5. R12最终验收
6. L01L02历史规则
7. 连锁触发验证
## 1. 环境证据边界
分别记录以下事件,未经批准不得互相替代:
- test环境部署成功。
- 生产环境流水线发布成功。
- 云效关联发布变更达到完成状态。
- 产品/业务验收完成。
流水线成功不等于测试用例通过test成功也不默认等于生产发布完成。
## 2. R11发布完成
优先使用“关联发布变更达到项目真实完成状态”作为R11证据。规则要求当前状态=`测试完成`,目标环境和发布证据满足组织口径。
如果组织明确把test部署定义为“完成发布”必须记录该口径的批准证据否则test回调只记录测试部署成功不推进发布完成。
## 3. CI02回调POC
1. 复制现有test流水线并使用明显POC名称。
2. 保留原test与prod流水线不变。
3. 只在副本Docker部署成功路径末尾添加回调。
4. 普通变量传工作项ID、环境、流水线执行ID。
5. 密钥变量保存认证材料,不写入仓库、命令输出或文档。
6. 请求携带时间戳、签名和执行ID幂等键。
7. 服务端校验需求当前状态,只允许预期流转执行一次。
8. 测试成功、重复回调、错误签名、超时、部署失败和安全重试。
9. POC通过后走推广评审不直接修改prod。
## 4. CI03证据分离
CI03要求项目配置分别保存test、prod、发布变更和验收证据。任何桥接都必须记录实现方式、启用状态、负责人、证据和人工回退。
回调失败保留失败日志并可安全重试不得伪造成功。同一执行ID重试不得多次推进需求。
## 5. R12最终验收
发布成功不等于业务验收。默认由产品/业务负责人确认后人工进入`已完成``已关闭`。只有可靠、可审计的验收任务才允许条件化自动关闭。
## 6. L01L02历史规则
- `L01``发布完成 + 全部关联任务完成/关闭 → 项目终态`。默认停用或收紧为独立验收任务,避免早期阶段任务误满足。
- `L02`:监听`测试完成 → 发布完成`状态路径并立即进入项目终态。默认停用,防止发布完成成为瞬时状态。
逐项目记录两条规则是否存在、是否启用、真实条件、顺序和证据;不存在也要有盘点证据。
## 7. 连锁触发验证
- 不按规则名称推断行为,逐条读取触发、条件、动作、顺序和执行账号。
- 每个目标状态都检查后继规则和重复规则。
- R11后至少观察两个时点刚进入发布完成时以及等待530秒后。
- 未经验收自动进入终态时,记录实际后继规则并判定`误触发`
- 跨两级以上流转必须有独立负向测试,不能只验证最终状态。

View File

@@ -1,97 +0,0 @@
# 云效自动化执行报告模板
```markdown
# 云效产品需求全生命周期自动化执行报告
## 1. 基本信息
- 组织:
- 项目:
- 工作项类型:
- 流程模型stage_tasks / oneos_delivery
- 迁移阶段仅oneos_deliveryP0 / P1 / P2 / P3
- 执行模式audit / plan / apply / test / document
- 执行时间:
- 执行账号:仅记录显示名,不记录凭据
## 2. 观察到的当前配置
| 项目 | 生命周期 | 标签 | 仓库/集成分支 | test流水线 | 发布证据 |
|---|---|---|---|---|---|
## 3. 规则变更
| 项目 | 规则 | 变更前 | 变更后 | 启用状态 | 复开核验 |
|---|---|---|---|---|---|
### 3.0 项目级规则实例
| 项目 | 规则ID | 云效规则显示名/人工门禁 | 精确触发事件 | 源状态 | 必要条件 | 动作/目标状态 | 顺序 | 启用 | 观察证据 |
|---|---|---|---|---|---|---|---:|---|---|
每个项目必须分别覆盖`R01``R12``TK01``TK08`。不得把一个项目的规则ID、显示名、顺序或证据复制为另一个项目的观察结果。
### 3.1 完整性台账
| 控制ID | 对象/流转 | 实现方式 | 启用状态 | 观察证据 | 负责人 | 回退方案 | 结论 |
|---|---|---|---|---|---|---|---|
每个项目必须分别覆盖全部31项`R01``R12``TK01``TK08``TC01``TC03``DF01``DF03``CI01``CI03``L01``L02`。不得把“规则编辑器不支持”写成“已完成”;应记录为`not_supported`并给出人工门禁或集成桥接方案。
`oneos_delivery`模型改用48项台账`Y01``Y16``Y20``Y22``Y30``Y35``Y40``A01``A02``A02B``A03``A10``TC01``TC03``DF01``DF03``CI01``CI03``L01``L02`
### 3.1a OneOS迁移就绪度
| 项目 | 目标状态缺口 | 主任务身份方式 | 原生规则能否过滤 | 任务工作流方案 | 桥接幂等/负责人 | 旧规则处置 | 结论 |
|---|---|---|---|---|---|---|---|
旧R/TK规则只有在目标状态、任务身份、任务工作流、桥接和回滚证据全部就绪后才能停用。`L01``L02`不受此等待条件影响,应保持停用以保护产品验收。
### 3.2 规则顺序与连锁触发
| 前置规则 | 目标状态 | 后继规则 | 是否自动二次流转 | 是否绕过验收 | 处理结论 |
|---|---|---|---|---|---|
## 4. 验证结果
| 用例 | 触发事件 | 期望状态 | 实际状态 | 结果分类 | 执行日志/证据 |
|---|---|---|---|---|---|
## 5. 研发资产覆盖
| 仓库 | dev/develop | 分支关联 | 提交关联 | MR关联 | 全部合并判断 |
|---|---|---|---|---|---|
## 6. 流水线与发布
| 流水线 | 环境 | 是否副本 | Docker部署 | 回调 | 是否影响prod |
|---|---|---|---|---|---|
## 7. 测试计划与缺陷闭环
| 测试计划 | 用例总数 | 已通过 | 未执行/待测试 | 阻塞 | 未通过 | 结论 |
|---|---:|---:|---:|---:|---:|---|
| 缺陷 | 关联用例/需求 | 修复状态 | 复测结果 | 最终状态 | 证据 |
|---|---|---|---|---|---|
| 失败用例 | 关联缺陷 | 缺陷已修复后用例状态 | 复测通过后用例状态 | 复测失败后用例状态 | 证据 |
|---|---|---|---|---|---|
## 8. 人工节点与剩余风险
- 真实开发开始时间:
- 业务验收:
- 发布完成是否被后继规则立即关闭:
- 全部关联任务范围:
- 多仓库漏关联风险:
- 其他:
- 范围外通用自动化通知、指派、SLA、字段同步等
## 9. 回滚
- 禁用新增规则:
- 恢复旧规则:
- 停用回调POC
- 测试资产清理(需授权):
```

View File

@@ -1,499 +0,0 @@
# 云效全流程角色与触发节点沟通话术
> 本文是异常处理和精细交接使用的详细版。日常操作优先读取`simple-role-commands.md`,使用“记录需求、开始分析、开始开发、提交测试、测试完成、发布成功、验收通过”等短口令。
## 目录
1. 使用规则
2. 通用话术骨架
3. 项目管理员与流程负责人
4. 产品负责人
5. 需求分析人员
6. 设计人员
7. 交付负责人
8. 技术负责人
9. 开发人员
10. 代码评审人员
11. 测试负责人和测试人员
12. 缺陷修复人员
13. 运维与发布负责人
14. 业务验收人员
15. 集成桥接负责人
16. 异常和催办话术
17. 节点交接清单
## 1. 使用规则
这套话术用于让不同角色把真实业务事件准确告诉Codex再由Codex审计、规划、执行获批修改、验证或形成报告。默认使用`yunxiao-requirement-lifecycle`
每次沟通至少提供:
- 精确项目名和需求编号。
- 当前角色、当前状态和刚刚发生的真实事件。
- 关联任务、仓库、分支、MR、测试计划、缺陷或流水线执行ID没有就明确写“无”。
- 希望Codex采用的权限`audit``plan``apply``test``document`
- 期望停在哪个状态,不要只说“继续流转”。
权限含义:
- `audit`:只核查和报告,不修改云效。
- `plan`:只输出修改方案和影响,不执行。
- `apply`:只修改话术中明确列出的项目、工作项或规则。
- `test`:使用隔离测试资产触发并收集证据。
- `document`:只形成说明、记录或报告。
必须遵守:
- 标题、需求编号、分支名或标签不能代替云效正式关联。
- 首次提交不代表真实开始开发;人工“开始处理”是效能主口径,分支关联只是自动兜底。
- `已修复`只表示交给测试复测,不是缺陷关闭。
- test部署成功不等于测试通过更不等于生产发布完成。
- 发布成功后停留`发布完成`,必须有产品或业务验收才能进入`已关闭`
- 未明确授权时,不改生产流水线、不直接推送保护分支、不删除规则或测试资产。
- 项目仍为`stage_tasks`时使用R/TK规则只有迁移门禁通过后才使用完整`oneos_delivery`链路。
## 2. 通用话术骨架
### 2.1 请求执行
```text
使用 yunxiao-requirement-lifecycle。
权限【audit/plan/apply/test/document】
项目:【精确项目名】
流程模型:【未知/stage_tasks/oneos_delivery】
我的角色:【角色】
需求:【需求编号+标题】
当前状态:【状态】
刚发生的事件:【真实事件】
相关资产:【任务/MR/分支/测试计划/缺陷/流水线执行ID没有写无】
期望结果:【目标状态或需要生成的资产】
请先核查当前状态和正式关联,再执行授权范围内动作;输出实际动作、触发结果、证据、未完成项和下一责任人。不要用手工改状态冒充自动化通过。
```
### 2.2 只核查为什么没有流转
```text
使用 yunxiao-requirement-lifecycle权限=audit。
项目:【项目名】,需求:【编号】,当前状态:【状态】。
我已执行:【事件】,相关对象:【对象编号或链接】;等待了【秒数】仍未流转。
请按事件、当前状态、标签位置、正式关联、规则启用、执行账号、执行日志、后继规则和异步窗口逐项诊断。不要直接替我改状态。
```
### 2.3 请求修改规则
```text
使用 yunxiao-requirement-lifecycle权限=apply。
只允许修改项目【项目名】中的规则【精确规则名/控制ID】目标是【目标】。
修改前备份触发、条件、动作、顺序、启用状态和执行账号;一次只改一条,保存后重新打开核对,并用隔离需求做正向和负向测试。禁止修改生产流水线及无关规则。
```
## 3. 项目管理员与流程负责人
### ADM01 项目首次审计或接管
触发:新项目接入、规则无人维护或准备复制到另一个项目。
```text
使用 yunxiao-requirement-lifecycle权限=audit。
请审计项目【项目名】先判断是stage_tasks、oneos_delivery还是迁移中。盘点工作流状态、标签、工作项类型、全部自动化规则、执行账号、前后端仓库、dev/develop、Testhub、缺陷状态、test/prod流水线、发布证据和验收门禁。
输出当前—目标差距、规则控制ID映射、风险、P0-P3实施顺序和不能自动化的人工门禁。不要修改线上配置。
```
完成证据:项目画像、规则清单、模型判断、缺口和迁移阶段齐全。
### ADM02 迁移到OneOS终态模型
触发:准备从阶段任务切换到交付主任务模型。
```text
使用 yunxiao-requirement-lifecycle权限=plan。
项目【项目名】准备迁移到oneos_delivery。请检查待测试、发布中、发布失败状态交付主任务识别方式开发/测试/发版任务工作流A03/A06/A08/A09幂等与负责人多仓库MR门禁、Testhub分包、生产证据和L01/L02状态。
只有十项迁移门禁全部通过才给出停用旧R/TK规则清单否则保留现网主链只列安全可做项和回滚方案。
```
完成证据:迁移门禁逐项结论,而不是笼统“可以迁移”。
### ADM03 规则变更后回归
触发:新建、修改、启停任何生命周期规则。
```text
使用 yunxiao-requirement-lifecycle权限=test。
项目【项目名】刚修改规则【规则名/控制ID】。请创建或复用隔离测试需求验证事件【事件】、源状态【状态】、目标状态【状态】并增加错误状态、无正式关联、部分MR、重复回调或后继连锁等负向场景。
结果只能记录为通过、异步通过、未触发、误触发或阻塞,并附执行日志和回滚入口。
```
### ADM04 定期治理
触发:季度检查、状态/标签重命名、新增仓库或人员离职。
```text
使用 yunxiao-requirement-lifecycle权限=audit。
请对项目【项目名】执行运行治理检查:规则执行账号和权限、失败日志、状态/标签重命名影响、新增仓库Webhook、多仓库MR覆盖、超过7天无活动分支、回调签名/幂等/重试、L01/L02以及生产和验收证据分离。
输出需要立即修复、计划修复和仅观察三类清单。
```
## 4. 产品负责人
### PO01 新建并确认需求
触发:需求范围、负责人、优先级和验收标准已明确。
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】需要建立需求【标题】。范围:【范围】;不包含:【排除项】;负责人:【姓名】;优先级:【级别】;目标迭代:【迭代】;验收标准:【标准】。
请先查重再创建或完善产品类需求。若项目为oneos_delivery校验唯一【交付】主任务若仍为stage_tasks不要擅自创建主任务。完成后告诉我需求编号、正式关系、当前状态和下一责任人。
```
### PO02 批准进入分析或快轨待开发
触发:需求确认后决定正常分析,或低风险小改走快轨。
正常路径:
```text
项目【项目名】需求【编号】已确认,批准进入分析。使用 yunxiao-requirement-lifecycle权限=apply。请核查范围、负责人和验收标准齐全再按当前流程模型触发分析入口不要跳过缺失信息。
```
快轨路径:
```text
项目【项目名】需求【编号】批准快轨到待开发,批准人【姓名】,原因【原因】,验收标准【标准】。使用 yunxiao-requirement-lifecycle权限=apply。请确认快轨边存在、唯一交付主任务已同步且没有循环风险缺少任一条件就停止并报告。
```
### PO03 需求范围变更
触发:开发或测试中修改范围。
```text
使用 yunxiao-requirement-lifecycle权限=plan。
项目【项目名】需求【编号】当前【状态】,拟变更:【新增/删除内容】;原因:【原因】;受影响资产:【开发任务/MR/用例/缺陷/发布范围】。
请先做影响分析列出需要重开或新增的任务、MR、用例和验收项以及是否应回退需求状态。未经我确认不要直接改状态或删除已有证据。
```
### PO04 产品验收通过并关闭
触发:生产发布完成,业务验收通过。
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】需求【编号】当前为发布完成。验收人【姓名】,验收时间【时间】,验收环境【生产】,验收结果【通过】,证据【链接/附件/记录】。
请核查生产发布证据与需求范围一致,并确认不存在未关闭验收项;满足后执行已关闭并回报审计证据。不得用流水线成功替代本次验收。
```
### PO05 验收不通过
```text
使用 yunxiao-requirement-lifecycle权限=plan。
项目【项目名】需求【编号】生产验收不通过。问题:【问题】;证据:【证据】;影响:【影响】。
请创建或关联可追踪缺陷/改进任务,建议应回到的真实状态和责任人;未经批准不要直接关闭需求或覆盖原发布记录。
```
## 5. 需求分析人员
### BA01 开始分析
```text
项目【项目名】需求【编号】由我开始分析,实际开始时间【时间】。使用 yunxiao-requirement-lifecycle权限=apply。请核查当前状态和我的关联任务将分析任务改为处理中并确认需求进入分析中如果项目为oneos_delivery则按主任务权威方向同步避免双向循环。
```
### BA02 分析完成
```text
项目【项目名】需求【编号】分析已完成。产物:【需求说明/流程/字段/边界链接】;未决项:【无或列表】;验收口径:【口径】。
使用 yunxiao-requirement-lifecycle权限=apply。请先检查分析任务非零且全部完成、产物可访问、未决项已处理再推进分析完成回报触发的是原生规则、桥接还是人工门禁。
```
## 6. 设计人员
### UX01 开始设计
```text
项目【项目名】需求【编号】开始设计,设计负责人【姓名】,原型地址【地址】,实际开始时间【时间】。使用 yunxiao-requirement-lifecycle权限=apply。请核查正式关联设计任务和当前状态再更新设计任务为处理中并确认需求进入设计中。
```
### UX02 设计完成并交接开发
```text
项目【项目名】需求【编号】设计完成。原型版本【版本】;设计稿【链接】;交互说明【链接】;响应式范围【范围】;已确认人【姓名】;遗留项【无或列表】。
使用 yunxiao-requirement-lifecycle权限=apply。请核查设计任务和交付物后完成设计阶段并检查是否只创建一组正确的开发任务。不要因为标题含“开发”就视为已正式关联。
```
完成证据:设计任务已完成、需求到设计完成;后继开发任务创建成功后才到待开发。
## 7. 交付负责人
### DL01 创建或核查唯一交付主任务
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】需求【编号】需要建立【交付】主任务,负责人【姓名】。请先按正式关系和交付标签查重;不存在才创建,存在一条则复用,存在多条则停止并列出冲突。主任务必须正式关联需求,不能只靠标题前缀。
```
### DL02 阶段同步异常
```text
使用 yunxiao-requirement-lifecycle权限=audit。
项目【项目名】需求【编号】状态【需求状态】,交付主任务【任务编号】状态【任务状态】,两者不一致。
请判断权威方向、检查Y01-Y16、来源防重和执行日志说明应补偿哪个对象。不要同时双向写入造成循环。
```
## 8. 技术负责人
### TL01 拆分开发任务
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】需求【编号】已到待开发。请按以下范围拆分开发任务:前端【范围/负责人/仓库】,后端【范围/负责人/仓库】,其他【范围】。每条任务必须正式关联需求和交付主任务、标签=开发、状态=待处理并记录目标dev/develop分支。查重后创建禁止重复任务。
```
### TL02 仅前端或仅后端需求
```text
项目【项目名】需求【编号】只涉及【前端/后端】,不涉及【另一端】。使用 yunxiao-requirement-lifecycle权限=apply。请只创建实际需要的开发任务并把不涉及的仓库明确记为不适用不要用缺少另一端MR阻塞也不要把未盘点仓库默认为已完成。
```
### TL03 开发完成门禁核查
```text
使用 yunxiao-requirement-lifecycle权限=audit。
项目【项目名】需求【编号】准备判定开发完成。相关仓库【列表】开发任务【列表】MR【列表及目标分支】。
请确认所有非取消开发任务完成、所有相关MR正式双关联并合并到真实dev/develop任一仓库未完成都保持开发中。输出缺口不要手工改成开发完成。
```
## 9. 开发人员
### DEV01 真实开始开发并创建分支
```text
使用 yunxiao-requirement-lifecycle权限=apply。
我开始处理项目【项目名】需求【编号】的开发任务【任务编号】真实开始时间【时间】仓库【仓库名】基线【dev/develop】拟建分支【feature/编号或fix/编号】。
请先确认基线真实存在且任务为待处理,再从基线创建或指导创建分支,并确保分支同时正式关联需求和开发任务。完成后核查需求=开发中、任务=处理中;不要用首次提交时间覆盖真实开始时间。
```
### DEV02 提交代码并创建MR
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】需求【编号】开发任务【任务编号】仓库【仓库】分支【分支】目标分支【dev/develop】。改动摘要【摘要】本地验证【命令和结果】。
请先拉取并检查冲突再按仓库规范提交、推送并创建MRMR必须正式关联需求和开发任务。不要直接推保护分支不要因为提交成功就把开发标为完成。
```
### DEV03 多仓库部分完成
```text
项目【项目名】需求【编号】目前仅仓库【仓库A】的MR【编号】已合并仓库【仓库B】仍在开发。使用 yunxiao-requirement-lifecycle权限=audit。请确认需求和交付主任务仍保持开发中并检查是否存在“部分MR导致提前完成”的误触发规则。
```
## 10. 代码评审人员
### REV01 评审要求修改
```text
项目【项目名】MR【编号】评审不通过需要修改【问题列表】。使用 yunxiao-requirement-lifecycle权限=document。请把评审结论关联到需求【编号】和开发任务【编号】确认MR保持未合并、开发任务保持处理中、需求保持开发中。
```
### REV02 MR合并后核查
```text
使用 yunxiao-requirement-lifecycle权限=audit。
项目【项目名】MR【编号】已合并到【dev/develop】关联需求【编号】、开发任务【编号】。请等待异步窗口后核查任务状态再汇总同需求所有仓库和MR。只有全部相关任务和MR完成才允许需求进入开发完成并确认测试任务只创建一条。
```
## 11. 测试负责人和测试人员
### QA01 建立测试任务和用例范围
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】需求【编号】开发已完成,目标迭代【迭代】,测试负责人【姓名】。请查重后创建或复用唯一【测试】任务,并将测试计划按需求编号建立独立用例包。范围:【功能/接口/权限/兼容/回归】;不适用:【列表】。正式关联需求、主任务和测试计划后进入待测试。
```
### QA02 test部署成功开始测试
```text
项目【项目名】需求【编号】的test部署成功流水线【名称】执行ID【ID】环境【test】部署时间【时间】。使用 yunxiao-requirement-lifecycle权限=apply。请校验执行ID、范围和重复回调再允许测试任务和需求进入测试中。明确记录本事件不能推进发布完成。
```
### QA03 用例失败并提交缺陷
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】需求【编号】测试计划【计划】用例【用例ID】执行失败。环境【环境】前置条件【条件】步骤【步骤】实际结果【实际】期望结果【期望】证据【截图/日志】;严重程度【级别】。
请查重后创建或关联缺陷,并把缺陷与原用例、需求正式关联。保持用例未通过、测试任务和需求测试中;不要把创建缺陷当作测试完成。
```
### QA04 缺陷复测通过
```text
项目【项目名】缺陷【编号】已在环境【环境】复测原用例【用例ID】重新执行通过证据【证据】复测人【姓名】时间【时间】。
使用 yunxiao-requirement-lifecycle权限=apply。请将原用例更新为通过并把缺陷进入项目真实关闭态随后重新核查本需求是否仍有未执行、阻塞、失败用例或未关闭缺陷。
```
### QA05 缺陷复测失败
```text
项目【项目名】缺陷【编号】复测失败原用例【用例ID】仍未通过。实际结果【结果】证据【证据】。
使用 yunxiao-requirement-lifecycle权限=apply。请重开缺陷或转回项目真实处理中状态保持原用例未通过、需求测试中并通知原修复负责人。不要保留“已修复/已关闭”。
```
### QA06 测试验收完成
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】需求【编号】申请完成测试。测试计划【计划】;用例包【范围】;执行统计【通过/失败/阻塞/未执行】;缺陷清单【编号+状态】;测试负责人【姓名】。
请按TC01-TC03和DF01-DF03核查。只有全部范围用例已执行并通过、失败用例已复测、缺陷由测试关闭时才完成测试任务并推进需求测试完成否则列出阻塞项。
```
## 12. 缺陷修复人员
### BUG01 接收缺陷并开始修复
```text
使用 yunxiao-requirement-lifecycle权限=apply。
我接收项目【项目名】缺陷【编号】关联需求【编号】、原用例【ID】开始修复时间【时间】仓库【仓库】拟用分支【fix/缺陷编号】。
请核查缺陷、需求和用例的正式关联再把缺陷转入真实处理中状态分支和MR同时关联缺陷、需求及对应开发任务。
```
### BUG02 修复完成交给测试
```text
项目【项目名】缺陷【编号】已修复。分支【分支】MR【编号】合并目标【dev/develop】验证结果【结果】部署环境【test/尚未部署】。
使用 yunxiao-requirement-lifecycle权限=apply。请核查代码和部署证据后把缺陷改为已修复并交给测试复测。不要关闭缺陷不要把原失败用例改为通过。
```
## 13. 运维与发布负责人
### OPS01 test部署回报
```text
使用 yunxiao-requirement-lifecycle权限=audit。
项目【项目名】test流水线【名称】执行【成功/失败】执行ID【ID】提交/MR范围【范围】时间【时间】。
请核查本次执行关联的需求和幂等记录。成功只允许测试开始;失败保持原状态并记录原因。不要触发生产发布完成。
```
### OPS02 创建迭代发版任务
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】迭代【迭代名/ID】准备发版计划窗口【时间】负责人【姓名】本批需求【编号列表】生产流水线【名称】。
请查重后创建或复用唯一【发版】任务,正式关联迭代和本批需求,并生成发布范围与回滚项。需求未测试完成或范围不一致时停止,不进入发布中。
```
### OPS03 开始生产发布
```text
项目【项目名】发版任务【编号】批准开始生产发布。审批人【姓名】;窗口【时间】;生产流水线【名称】;本批需求【列表】;回滚方案【链接】。
使用 yunxiao-requirement-lifecycle权限=apply。请核查全部需求测试完成、范围一致和审批证据再进入发布中。只操作明确的生产发布不修改流水线定义。
```
### OPS04 生产发布成功
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】生产流水线【名称】执行成功执行ID【ID】环境【prod】完成时间【时间】发布范围【需求/MR/版本】,证据【链接】。
请验证签名、时间戳、执行ID幂等和范围推进发版任务及本批需求到发布完成并停留通知产品验收。禁止自动进入已关闭。
```
### OPS05 生产发布失败或重试
失败:
```text
项目【项目名】生产流水线【名称】执行失败执行ID【ID】失败阶段【阶段】原因【原因】影响需求【列表】回滚结果【结果】。
使用 yunxiao-requirement-lifecycle权限=apply。请记录失败证据并推进到发布失败不得伪造成功或关闭需求。
```
重试:
```text
项目【项目名】发版任务【编号】批准从发布失败重试批准人【姓名】新执行ID【ID】已修正原因【说明】。
使用 yunxiao-requirement-lifecycle权限=apply。请核查发布失败→发布中流转边、幂等键和范围后开始重试保留原失败记录。
```
## 14. 业务验收人员
### ACC01 验收通过
```text
我是业务验收人【姓名】。项目【项目名】需求【编号】已在生产环境按验收项【列表】验证通过,时间【时间】,证据【链接/附件】。
使用 yunxiao-requirement-lifecycle权限=apply。请核查身份、发布完成状态和证据范围后关闭需求并保留验收记录。
```
### ACC02 验收不通过
```text
我是业务验收人【姓名】。项目【项目名】需求【编号】生产验收不通过,失败项【列表】,实际结果【结果】,证据【证据】。
使用 yunxiao-requirement-lifecycle权限=plan。请建立可追踪问题清单分析应回到测试、开发还是重新发布并指定下一责任人不要关闭需求。
```
## 15. 集成桥接负责人
### INT01 回调未生效或重复
```text
使用 yunxiao-requirement-lifecycle权限=audit。
桥接控制【A03/A06/A08/A09/其他】项目【项目名】需求【编号】事件ID【ID】时间戳【时间】回调结果【未生效/重复/失败】,日志摘要【摘要】。
请核查签名、时间窗、防重放、幂等键、当前状态、权限、重试和审计日志。不要绕过校验直接补写状态;给出安全重试或人工回退方案。
```
### INT02 幂等补偿
```text
使用 yunxiao-requirement-lifecycle权限=apply。
项目【项目名】控制【控制ID】需要补偿原事件ID【ID】期望对象【任务/状态】,当前对象【实际】。已确认原操作未成功且不存在重复对象。
请再次查询幂等键和正式关系只补偿缺失动作完成后输出新旧事件关联、对象ID和重复检查证据。
```
## 16. 异常和催办话术
### 状态长时间不动
```text
项目【项目名】需求/任务【编号】在【状态】停留【时长】,最后真实事件【事件】,负责人【姓名】,关联资产【列表】。使用 yunxiao-requirement-lifecycle权限=audit。请判断是业务未完成、自动化未触发还是异步失败并给出下一责任人和最小恢复动作不要直接跳状态。
```
### 状态被提前推进
```text
项目【项目名】需求【编号】从【源状态】意外进入【目标状态】,时间【时间】。使用 yunxiao-requirement-lifecycle权限=audit。请检查后继规则、全部关联项口径、部分MR、未复测缺陷、test/prod混用和L01/L02定位真实触发规则并给出回滚建议。未经确认不要回退状态。
```
### 任务重复创建
```text
项目【项目名】需求【编号】出现重复【交付/开发/测试】任务:【任务列表】。使用 yunxiao-requirement-lifecycle权限=audit。请检查幂等键、正式关系和重复回调确定保留项及合并/取消方案。未经授权不要删除任务。
```
## 17. 节点交接清单
每次角色交接都让Codex确认以下内容
1. 项目、需求、任务和流程模型准确。
2. 源状态与目标状态明确。
3. 事件真实发生,且正式关联可见。
4. 当前责任人和下一责任人明确。
5. 交付物、代码、用例、缺陷或发布证据可访问。
6. 正向条件全部满足,负向阻塞项为零。
7. 自动化结果与人工准备动作分开记录。
8. 异步等待后重新核查状态和执行日志。
9. 没有误触发后继规则或重复创建。
10. 回滚入口、人工回退和未完成事项已记录。
Codex的节点回报统一使用
```text
项目:
流程模型:
工作项:
源状态 → 实际状态:
本次真实事件:
执行动作:
触发方式:原生规则/桥接/人工门禁/未触发
验证结果:通过/异步通过/未触发/误触发/阻塞
证据:
未完成项:
下一责任角色:
允许的下一动作:
回滚入口:
```

View File

@@ -1,417 +0,0 @@
# 云效日常口语化操作口令
## 1. 先说一次项目
每次新会话先输入:
```text
项目统一运营管理平台PC端
```
之后直接说口令即可。项目没有明确、同一编号可能属于多个项目或用户切换项目时Codex必须先问清项目不能猜。
口令可以自然表达,不要求标点完全一致。例如:
- `记录需求:增加车辆批量导出`
- `帮我记录一个需求,增加车辆批量导出`
两句话含义相同。
## 2. 产品和需求
### 记录需求
产品输入:
```text
记录需求:增加车辆批量导出
```
Codex执行查重后在当前项目创建产品类需求初始状态为`待处理`,返回需求编号。只有标题也可以先记录;云效必填字段缺失时只追问缺少的字段。
**带模块/原型的记录OneOS** 若口令含模块名或原型(如「记录需求:保险采购」),创建前**先调用 `$oneos-autoprd`**,把「需求说明」写入描述;若用户同时定稿,一并写入「更新内容」。
**统一运营管理平台 · 快路径(强制):** 项目为「统一运营管理平台 / PC 端」时,先读 [oneos-pc-fast-path.md](oneos-pc-fast-path.md) 与 [oneos-pc-runtime-ids.json](../assets/oneos-pc-runtime-ids.json)。用已验证 `POST /workitem/workitem` 建单(创建时带 `document`),不要探测 `/workitem/create`。推进至「开发中」时状态连跳:`待处理 → 设计完成 → 待开发 → 开发中`
**优先级 / 推进至 Plan 单选门禁(强制):** 用户要求 Plan 模式单选,或口令含「优先级」「推进至」需点选时:
1. 先用 `AskQuestion`(可用时)或 Plan 确认拿到 A紧急/高/中/低)与 B分析中/设计中/设计完成/开发中)。
2. **禁止**未选时默认「中 + 分析中」并继续建单。
3. 「批准 / Implement 计划」本身不等于已选 A+B计划里仍是空选项时必须先问清。
4. 标签须用户从云效标签 catalog`oneos-pc-tag-catalog.md`)点选;禁止按业务条线说明/`lines.ts` 自动推断。点选后 API 打标,失败则停并请用户回复标签名,禁止假装成功。
**完整可复制提示词(推荐):** 统一运营管理平台建单优先用 [oneos-pc-record-requirement-prompt.md](oneos-pc-record-requirement-prompt.md)——含 `$yunxiao-requirement-lifecycle` + `$oneos-autoprd`、A/B/C 三门禁与 30 项标签枚举。复制该文件「用户口令」整段发给 Agent确认后再执行快路径。
简短版(填需求名与模块后复制):
```text
使用 $yunxiao-requirement-lifecycle + $oneos-autoprd
记录需求到云效 · 统一运营管理平台
【需求名】(填写)
【描述来源】$oneos-autoprd原型/模块:(填写)
请先 Plan 让我点选 A 优先级、B 推进至、C 标签30 项 catalog见 oneos-pc-record-requirement-prompt.md禁止 lines.ts 推断)。
我确认后再执行快路径建单。
```
确认回复示例:`优先级:高;推进至:设计完成;标签:运维管理条线`
### 确认需求
产品输入:
```text
确认需求ONEOSP-123
```
Codex执行检查范围、负责人、优先级和验收标准齐全后把需求改为`已确认`
`确认需求`默认不创建分析任务。确认和真实开始分析是两个事件,防止开始时间失真。由分析人员下一步输入`开始分析`
### 需求定稿(原型 + AutoPRD
产品输入:
```text
保险采购需求定稿
```
或:
```text
需求定稿ONEOSP-123模块=保险采购
```
Codex执行
1. 调用 `$oneos-autoprd` 定稿流程:更新原型 `.spec/requirements-prd.md` 第 10 章「功能变更记录」与 `autoprd-baseline.json`(只记功能/逻辑,不记样式/UI/表结构)。
2. 若已有云效需求编号:刷新描述中的「需求说明」与「更新内容」;旧更新内容 →「更新内容·历史」。
3. 若口令要求进待开发/发对象存储:继续走下方「快速进入开发」或 OneOS 快轨口令,不得跳过 AutoPRD。
### 快速进入开发
产品输入:
```text
快速开发ONEOSP-123原因=小改动;负责人=张三;范围=只改后端
```
Codex执行检查项目是否允许快轨、验收标准是否明确再跳过不需要的分析/设计阶段并建立必要开发任务。条件不齐时不跳状态,只提示缺少什么。
**OneOS 模块已定型进待开发(推荐):**
```text
「保险采购」需求已经确定:先 AutoPRD 写需求说明与更新内容;发布对象存储并写入描述;
推进到待开发;自动建与需求同名的【交付】任务并正式关联;负责人何斐。
```
执行前必须先跑 `$oneos-autoprd`(含定稿变更记录若用户刚定稿)。进入待开发时**必须**执行 [auto-stage-task.md](auto-stage-task.md)(同名任务、标签交付、负责人何斐、时间沿用需求);已有唯一交付任务则复用并改负责人为何斐,禁止建第二条。
### 需求变更
产品输入:
```text
变更需求ONEOSP-123增加导出时间筛选
```
Codex执行先分析受影响的任务、MR、用例、缺陷和发布范围给出应回到哪个阶段产品确认后再修改不直接覆盖历史说明。涉及原型功能变更时同步 `$oneos-autoprd` 更新 PRD用户再说「定稿」时写入第 10 章。
## 3. 分析和设计
### 开始分析
分析人员输入:
```text
开始分析ONEOSP-123负责人=李四
```
Codex执行
1. 将需求推进到`分析中`(或确认已在分析中)。
2. **按 [auto-stage-task.md](auto-stage-task.md)**:查重后创建/复用与需求**同名**任务;标签=`分析`;正式关联需求;负责人默认=需求**创建人**(口令写了负责人则用口令);计划开始/创建时间沿用需求。
3. 任务进入`处理中`(或项目约定的开工态)。
4. `stage_tasks`:需求标签含`分析``oneos_delivery`:不因此再建第二条【交付】主任务。
### 分析完成
分析人员输入:
```text
分析完成ONEOSP-123说明=https://...
```
Codex执行检查分析产物和未决项完成对应任务或主任务阶段核查需求进入`分析完成`
### 开始设计
设计人员输入:
```text
开始设计ONEOSP-123负责人=王五
```
Codex执行
1. 将需求推进到`设计中`
2. **按 auto-stage-task**:同名任务;标签=`设计`;正式关联;负责人默认=需求**创建人**(口令可覆盖);时间沿用需求。
3. 任务开工态同上。
4. `oneos_delivery`:不同时新建交付主任务(交付主任务在待开发时建/复用)。
### 设计完成
设计人员输入:
```text
设计完成ONEOSP-123原型=https://...
```
Codex执行检查原型或设计说明完成设计任务/主任务阶段,核查需求进入`设计完成`
如果项目已经部署并验证自动建开发任务的桥接而且负责人、仓库和范围明确Codex继续查重并创建开发任务否则停在`设计完成`,提示技术负责人输入`安排开发`。不得创建无负责人或重复任务。
**进入待开发时(含快轨):** 必须再跑 auto-stage-task同名任务、标签`交付`(或`开发`)、负责人**何斐**、正式关联、时间沿用需求。
## 4. 开发
### 安排开发
技术负责人输入:
```text
安排开发ONEOSP-123前端=张三/ln-one-os-web后端=李四/ln-cloud
```
只改一端时可以说:
```text
安排开发ONEOSP-123只改后端=李四/ln-cloud
```
Codex执行按实际范围创建一条或多条`【开发】`任务,正式关联需求;`oneos_delivery`还要关联交付主任务。任务初始为`待处理`,需求进入`待开发`。明确“不涉及”的仓库不会成为完成门禁。
### 开始开发
开发人员输入:
```text
开始开发ONEOSP-123任务=TASK-456仓库=ln-cloud
```
Codex执行记录真实开始时间确认真实基线`dev``develop`,创建`feature/ONEOSP-123`并同时正式关联需求和开发任务。任务进入`处理中`,需求进入`开发中`
首次提交只作兜底,不覆盖这次真实开始时间。
### 提交代码
开发人员输入:
```text
提交代码ONEOSP-123任务=TASK-456仓库=ln-cloud
```
Codex执行检查改动和测试先拉取并处理冲突再提交、推送并创建合并到真实`dev/develop`的MRMR同时关联需求和开发任务。提交成功不等于开发完成。
### 开发完成
开发人员或技术负责人输入:
```text
开发完成ONEOSP-123
```
Codex执行汇总该需求所有非取消开发任务、前后端仓库和正式关联MR。只有全部任务完成、全部相关MR已合并才确认需求进入`开发完成`;少一个仓库也不提前完成。
条件满足后,如果项目已配置并验证唯一测试任务桥接,则查重创建测试任务;否则提示测试负责人输入`提交测试`
## 5. 测试和缺陷
### 提交测试
测试负责人或开发负责人输入:
```text
提交测试ONEOSP-123test流水线=oneos-web-test
```
Codex执行确认开发完成触发或核查明确的test流水线。部署成功后查重创建并正式关联唯一测试任务和需求用例包进入`待测试/测试中`的项目真实状态。
test成功只允许开始测试不能变成发布完成。
### 开始测试
测试人员输入:
```text
开始测试ONEOSP-123负责人=赵六
```
Codex执行核查test部署和测试任务把测试任务改为`测试中/处理中`,需求进入`测试中`
### 发现Bug
测试人员输入:
```text
发现BugONEOSP-123用例=CASE-12现象=车辆来源显示0期望=显示中文来源
```
Codex执行查重后创建缺陷正式关联需求、原失败用例和必要开发任务用例保持未通过需求保持`测试中`
### Bug修复完成
开发人员输入:
```text
Bug修复完成BUG-123MR=456已部署test
```
Codex执行核查代码、MR和test部署后把缺陷改为`已修复`并交给测试复测。不会关闭缺陷,也不会把原用例直接改成通过。
### 复测通过
测试人员输入:
```text
复测通过BUG-123用例=CASE-12
```
Codex执行重新记录原用例为通过把缺陷改为项目真实关闭态再检查该需求是否还有失败、阻塞、未执行用例或未关闭缺陷。
### 复测失败
测试人员输入:
```text
复测失败BUG-123用例=CASE-12现象=仍显示0
```
Codex执行原用例保持未通过缺陷重开或回到处理中并通知修复负责人需求保持`测试中`
### 测试完成
测试负责人输入:
```text
测试完成ONEOSP-123
```
Codex执行检查本需求用例包不按整个迭代一刀切。只有没有未执行、阻塞、失败用例且所有缺陷都经过测试复测关闭才完成测试任务并推进需求到`测试完成`
## 6. 发布和验收
### 准备发布
运维或项目负责人输入:
```text
准备发布迭代V1.3;需求=ONEOSP-123,ONEOSP-124窗口=今晚22:00
```
Codex执行检查本批需求均测试完成查重创建或复用唯一`【发版】`任务,正式关联迭代和需求,生成发布范围及回滚清单。
### 开始发布
运维输入:
```text
开始发布:发版任务=TASK-900prod流水线=oneos-prod审批人=王经理
```
Codex执行核查审批、本批范围、生产流水线和回滚方案后进入`发布中`。这句话授权执行明确的本次生产发布,但不授权修改生产流水线定义。
### 发布成功
运维输入:
```text
发布成功执行ID=PIPE-789发版任务=TASK-900
```
Codex执行到生产流水线核查环境、执行ID、范围和成功证据确认后推进本批需求到`发布完成`并停留,等待验收。只说“成功”但没有生产证据时不改状态。
### 发布失败
运维输入:
```text
发布失败执行ID=PIPE-789原因=镜像拉取失败
```
Codex执行核查失败证据记录原因并进入项目真实`发布失败`状态;项目尚无该状态时记录阻塞并给出人工处置,不创建近义重复状态。
### 验收通过
产品或业务输入:
```text
验收通过ONEOSP-123验收人=王经理;证据=https://...
```
Codex执行核查生产发布完成和验收证据后把需求改为`已关闭`。发布成功不能代替本句验收。
### 验收不通过
产品或业务输入:
```text
验收不通过ONEOSP-123问题=导出字段缺失
```
Codex执行创建或关联可追踪问题判断应回到开发、测试还是重新发布先给出处理建议不关闭需求不覆盖原发布记录。
## 7. 随时可用的查询口令
```text
查状态ONEOSP-123
下一步ONEOSP-123
为什么没流转ONEOSP-123
查重复任务ONEOSP-123
查关联代码ONEOSP-123
查测试闭环ONEOSP-123
给我回滚方案:刚才那条规则
```
这些口令默认只查询或出方案,不修改云效。
## 8. Codex的简短回报格式
处理成功:
```text
已处理ONEOSP-123
状态:已确认 → 分析中
任务:已创建并关联分析任务 TASK-456
下一步分析人员输入“分析完成ONEOSP-123说明=链接”
```
条件不足:
```text
暂未处理ONEOSP-123
缺少:开发负责人
请补充安排开发ONEOSP-123只改后端=负责人/仓库
```
自动化未触发:
```text
未触发ONEOSP-123 仍为待开发
原因:分支只写了需求编号,没有在云效正式关联开发任务
下一步:我可以补正式关联,然后再核查一次
```
## 9. Codex执行口令的规则
1. `记录、确认、开始、完成、提交、修复、复测、准备发布、发布、验收`属于当前项目和明确工作项的执行授权。
2. `查、看看、为什么、下一步、给方案`只允许读取或规划。
3. 写操作前必须确认当前项目;项目不清楚只问项目名。
4. 其他必要字段缺失时只追问最少信息,不发送长表单。
5. 先查重、再创建任务幂等键使用项目ID、需求ID和阶段类型。
6. 项目使用`stage_tasks`还是`oneos_delivery`由Codex识别同事不需要记规则编号。
7. 当前平台或桥接不支持的动作要明确说“需要人工一步”,不能伪装成已自动化。
8. 自动规则执行后等待530秒再回看状态、正式关联和执行日志。
9. 不用手工改最终状态冒充自动化通过。
10. 不修改生产流水线定义不删除规则、分支、MR、任务或测试资产除非用户单独明确授权。

View File

@@ -1,87 +0,0 @@
# 阶段任务生命周期与自动创建
## 目录
1. 目标链路
2. TK01TK08规则
3. 关系与代码资产
4. 原生规则和桥接边界
5. 验证与回滚
## 1. 目标链路
```text
需求设计中 + 设计任务处理中
→ 设计任务已完成
→ 需求设计完成
→ 创建并关联开发任务
→ 需求待开发 + 开发任务待处理
→ 正式关联需求分支
→ 需求开发中 + 开发任务处理中
→ 全部相关MR合并到真实dev/develop
→ 需求开发完成 + 开发任务已完成
→ test流水线部署成功
→ 创建并关联测试任务
→ 需求测试中 + 测试任务处理中
→ 用例全部通过且缺陷复测关闭
→ 需求测试完成 + 测试任务已完成
```
分支只能合并到集成分支不能“合并到测试环境”。test环境由流水线部署部署成功用于允许测试开始不用于证明生产发布。
## 2. TK01TK08规则
| ID | 触发 | 必要条件 | 动作 | 推荐实现 |
|---|---|---|---|---|
| TK01 | 需求进入设计中 | 已正式关联设计任务;任务标签=`设计` | 设计任务保持待处理,负责人真实开工后人工改为处理中 | 默认+人工 |
| TK02 | 设计任务变为已完成 | 需求当前状态=设计中;本阶段设计任务非零且全部完成 | 需求改为设计完成 | 原生规则 |
| TK03 | 需求变为设计完成 | 不存在同需求、同阶段、未取消的开发任务 | 创建并正式关联开发任务,标签=`开发`,状态=待处理 | API/Webhook桥接 |
| TK04 | 开发任务创建并关联成功 | 需求当前状态=设计完成;开发任务关系可见 | 需求改为待开发 | 原生规则 |
| TK05 | 正式关联需求分支/代码资产 | 需求=待开发;开发任务=待处理;资产同时关联需求和开发任务 | 需求改为开发中;开发任务改为处理中 | 原生规则 |
| TK06 | 关联合并请求状态变化 | 需求=开发中;开发任务=处理中全部相关前后端MR已合并到真实集成分支 | 需求改为开发完成;开发任务改为已完成 | 原生规则 |
| TK07 | test流水线部署成功 | 需求=开发完成执行ID未处理不存在同需求、同阶段、未取消的测试任务 | 创建并关联测试任务,关联测试计划/用例,任务改为处理中,需求改为测试中 | API/Webhook桥接 |
| TK08 | 测试验收完成 | 用例全部通过;失败用例已复测;范围内缺陷均由测试关闭 | 测试任务改为已完成;需求改为测试完成 | 桥接/人工门禁 |
## 3. 关系与代码资产
- 设计、开发、测试任务必须使用云效正式父子项或关联项关系,不依赖标题关键字。
- 开发分支和MR必须同时关联产品需求与对应开发任务只关联需求不能可靠更新开发任务。
- 一个需求涉及多个仓库时全部相关前端、后端MR都纳入TK06门禁。
- 首次提交可能晚于真实开工。任务`处理中`的权威时间是负责人执行“开始处理”;分支关联仅作自动兜底。
## 4. 原生规则和桥接边界
优先使用云效原生规则处理状态变化、父子项、关联项和Codeup对象。若当前规则编辑器没有“创建工作项”动作TK03和TK07必须标记为`integration_bridge``not_supported`,不得声称已经自动创建。
桥接创建任务时使用幂等键:
```text
项目ID + 需求ID + 阶段类型
```
重复回调先查询是否存在未取消的同阶段任务存在则复用并校验正式关系不重复创建。流水线回调还要校验签名、时间戳、执行ID、防重放和失败重试。
## 5. 验证与回滚
- 正向验证每个TK控制并检查需求和任务两个对象的状态。
- 负向验证零任务、错误标签、错误当前状态、未正式关联分支、只合并部分MR、流水线失败和重复回调。
- 新规则不会补触发历史事件。历史任务仅在核对MR/流水线证据后人工修正,并标记为测试准备或数据修复。
- 回滚时先禁用新增规则或桥接入口,不删除已有任务和关系;恢复前一状态需要单独业务确认。
## 6. 进阶段自动建同名任务(与 OneOS / 口令共用)
完整规则见 [auto-stage-task.md](auto-stage-task.md)。摘要:
| 需求状态 | 同名任务标签 | 负责人 |
|---|---|---|
| 分析中 | `分析` | 需求创建人 |
| 设计中 | `设计` | 需求创建人 |
| 待开发 | `交付``开发` | 何斐 |
必须正式关联需求;计划开始/创建时间沿用需求;同阶段幂等查重。
当创建或修复**分析 / 设计 / 交付(开发)**任务时:
1. **任务标签(右侧基础字段)**:分析 → `分析`;设计 → `设计`;待开发主任务 → `交付`(或 `开发`。Title 同名或前缀 alone 不够。
2. **正式关联需求**:每条阶段任务必须链接到**产品需求**(父子或关联项)。只关联其他任务不算完成。
3. 创建/修复后先核对标签与可见需求关系,再报告成功。

View File

@@ -1,62 +0,0 @@
# 测试用例与缺陷复测闭环
## 目录
1. 测试完成门槛
2. TC01TC03用例控制
3. DF01DF03缺陷控制
4. 实现方式
5. 验证场景
## 1. 测试完成门槛
R10只有同时满足以下条件才能完成
1. 范围内用例均已执行并有明确结果。
2. 不存在`未执行/待测试``阻塞``未通过`用例;获批暂缓/不适用项记录批准人与原因。
3. 每个未通过用例均正式创建或关联缺陷。
4. 修复后重新执行原用例并通过。
5. 范围内缺陷均由测试复测并进入项目真实关闭态。
6. 测试计划或测试验收任务由测试负责人确认。
流水线成功只能证明部署/自动检查成功,不能替代用例结果和缺陷复测。
## 2. TC01TC03用例控制
| ID | 控制 | 完成口径 |
|---|---|---|
| TC01 | 用例执行 | 每条范围内用例有真实执行结果;未执行、待测试、阻塞、未通过均阻塞测试完成 |
| TC02 | 失败用例关联缺陷 | 每条未通过用例正式创建或关联缺陷;仅写编号或链接不算关联 |
| TC03 | 用例复测更新 | 修复后重新执行原用例;通过才改为已通过,失败保持未通过 |
## 3. DF01DF03缺陷控制
| ID | 控制 | 完成口径 |
|---|---|---|
| DF01 | 已修复交接 | `已修复`只表示开发交给测试复测,不是终态,不解除测试门禁 |
| DF02 | 复测通过 | 缺陷进入项目真实关闭态,原失败用例同时更新为已通过 |
| DF03 | 复测失败 | 缺陷进入项目真实重开/处理中状态,原用例保持未通过 |
不得关闭缺陷却不更新原用例,也不得在缺陷仅为`已修复`时把用例标为通过。
## 4. 实现方式
先检查当前规则编辑器是否真的暴露Testhub执行用例和缺陷聚合条件
- 支持时:使用原生聚合规则,并保存条件和执行日志证据。
- 不支持时:使用测试验收任务/人工门禁。
- 需要全自动时单独评审Testhub OpenAPI/Webhook桥接要求签名、幂等、失败重试和审计记录。
不能把`not_supported`写成“已自动化”;必须指定负责人和回退方案。
## 5. 验证场景
| 场景 | 操作 | 期望 | 负向检查 |
|---|---|---|---|
| 用例未执行 | 保留一条未执行用例 | 保持测试中 | 不得完成测试 |
| 用例失败 | 记录未通过并正式关联缺陷 | 保持测试中 | 仅建缺陷不得完成 |
| 缺陷已修复 | 开发改为已修复 | 等待测试复测 | 不得关闭或通过用例 |
| 复测通过 | 重跑原用例并通过 | 用例通过、缺陷关闭 | 两者状态必须一致 |
| 复测失败 | 重跑仍失败 | 用例未通过、缺陷重开 | 不得保持已修复/关闭 |
| 全部闭环 | 全部用例通过且缺陷关闭 | 允许R10推进 | 检查是否误触发后继规则 |

View File

@@ -1,314 +0,0 @@
#!/usr/bin/env python3
"""Validate and render a OneOS delivery-model Yunxiao project profile."""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from typing import Any
TARGET_LIFECYCLE = [
"待处理", "已确认", "分析中", "分析完成", "设计中", "设计完成",
"待开发", "开发中", "开发完成", "待测试", "测试中", "测试完成",
"发布中", "发布完成", "发布失败", "已关闭",
]
REQUIRED_TASK_LABELS = {"交付", "开发", "测试", "发版"}
REQUIRED_CONTROL_IDS = {
*(f"Y{index:02d}" for index in range(1, 17)),
"Y20", "Y21", "Y22",
*(f"Y{index:02d}" for index in range(30, 36)),
"Y40",
"A01", "A02", "A02B", *(f"A{index:02d}" for index in range(3, 11)),
*(f"TC{index:02d}" for index in range(1, 4)),
*(f"DF{index:02d}" for index in range(1, 4)),
*(f"CI{index:02d}" for index in range(1, 4)),
"L01", "L02",
}
VALID_MODES = {
"manual", "native_rule", "integration_bridge", "disabled_legacy", "not_supported"
}
VALID_PHASES = {"P0", "P1", "P2", "P3"}
VALID_TASK_WORKFLOW_MODES = {"A", "B"}
VALID_TASK_IDENTITY_MODES = {"work_item_type", "task_label", "title_prefix_process_control"}
VALID_LEGACY_DISPOSITIONS = {"keep_until_ready", "disable", "replace", "already_disabled"}
SENSITIVE_FRAGMENTS = (
"password", "passwd", "secret", "token", "cookie", "credential",
"private_key", "otp", "密码", "密钥",
)
def is_text(value: Any) -> bool:
return isinstance(value, str) and bool(value.strip())
def require_text(container: dict[str, Any], key: str, label: str, errors: list[str]) -> None:
if not is_text(container.get(key)):
errors.append(f"{label}.{key} 不能为空")
def walk_sensitive_keys(value: Any, prefix: str = "") -> list[str]:
found: list[str] = []
if isinstance(value, dict):
for key, nested in value.items():
current = f"{prefix}.{key}" if prefix else str(key)
if any(fragment in str(key).lower() for fragment in SENSITIVE_FRAGMENTS):
found.append(current)
found.extend(walk_sensitive_keys(nested, current))
elif isinstance(value, list):
for index, nested in enumerate(value):
found.extend(walk_sensitive_keys(nested, f"{prefix}[{index}]"))
return found
def validate_controls(controls: Any, label: str, errors: list[str]) -> None:
if not isinstance(controls, list):
errors.append(f"{label} 必须是数组")
return
seen: set[str] = set()
for index, control in enumerate(controls):
item_label = f"{label}[{index}]"
if not isinstance(control, dict):
errors.append(f"{item_label} 必须是对象")
continue
control_id = control.get("id")
if not is_text(control_id):
errors.append(f"{item_label}.id 不能为空")
continue
if control_id in seen:
errors.append(f"{label} 控制项重复:{control_id}")
seen.add(control_id)
if control_id not in REQUIRED_CONTROL_IDS:
errors.append(f"{label} 未知控制项:{control_id}")
mode = control.get("mode")
if mode not in VALID_MODES:
errors.append(f"{item_label}.mode 不合法")
if not isinstance(control.get("enabled"), bool):
errors.append(f"{item_label}.enabled 必须是布尔值")
if mode in {"disabled_legacy", "not_supported"} and control.get("enabled") is not False:
errors.append(f"{item_label}{mode} 模式要求 enabled=false")
if control_id in {"L01", "L02"}:
if mode != "disabled_legacy" or control.get("enabled") is not False:
errors.append(f"{item_label} 必须停用,防止发布完成绕过验收")
for key in ("owner", "fallback", "evidence"):
require_text(control, key, item_label, errors)
missing = sorted(REQUIRED_CONTROL_IDS - seen)
if missing:
errors.append(f"{label} 缺少控制项:" + "".join(missing))
def validate_project(project: Any, index: int, errors: list[str]) -> None:
label = f"projects[{index}]"
if not isinstance(project, dict):
errors.append(f"{label} 必须是对象")
return
require_text(project, "name", label, errors)
if project.get("migration_phase") not in VALID_PHASES:
errors.append(f"{label}.migration_phase 必须是 P0/P1/P2/P3")
statuses = project.get("requirement_statuses_observed")
if not isinstance(statuses, list) or not statuses or not all(is_text(v) for v in statuses):
errors.append(f"{label}.requirement_statuses_observed 必须是非空文本数组")
if project.get("task_workflow_mode") not in VALID_TASK_WORKFLOW_MODES:
errors.append(f"{label}.task_workflow_mode 必须是 A 或 B")
if project.get("task_identity_mode") not in VALID_TASK_IDENTITY_MODES:
errors.append(f"{label}.task_identity_mode 不合法")
if not isinstance(project.get("native_rule_can_filter_related_task_identity"), bool):
errors.append(f"{label}.native_rule_can_filter_related_task_identity 必须是布尔值")
for key in (
"main_task_prefix", "development_task_prefix", "test_task_prefix", "release_task_prefix"
):
require_text(project, key, label, errors)
repositories = project.get("repositories")
if not isinstance(repositories, list) or not repositories:
errors.append(f"{label}.repositories 至少包含一个仓库")
else:
for repo_index, repo in enumerate(repositories):
repo_label = f"{label}.repositories[{repo_index}]"
if not isinstance(repo, dict):
errors.append(f"{repo_label} 必须是对象")
continue
for key in ("name", "role", "integration_branch", "evidence"):
require_text(repo, key, repo_label, errors)
if repo.get("integration_branch") not in {"dev", "develop"}:
errors.append(f"{repo_label}.integration_branch 只能是实际存在的 dev/develop")
for key in ("codeup_integrated", "required_for_mr_gate"):
if not isinstance(repo.get(key), bool):
errors.append(f"{repo_label}.{key} 必须是布尔值")
test_plan = project.get("test_plan")
if not isinstance(test_plan, dict):
errors.append(f"{label}.test_plan 必须是对象")
else:
require_text(test_plan, "name", f"{label}.test_plan", errors)
require_text(test_plan, "evidence", f"{label}.test_plan", errors)
for key, required in (
("iteration_formally_related", True),
("cases_partitioned_by_requirement", True),
("fixed_defect_is_terminal", False),
("tester_retest_required", True),
):
if test_plan.get(key) is not required:
errors.append(f"{label}.test_plan.{key} 必须为 {str(required).lower()}")
release = project.get("release")
if not isinstance(release, dict):
errors.append(f"{label}.release 必须是对象")
else:
require_text(release, "evidence", f"{label}.release", errors)
for key in (
"release_task_formally_related_to_iteration",
"production_evidence_separate_from_test",
"acceptance_required_after_release",
"production_pipeline_unchanged",
):
if release.get(key) is not True:
errors.append(f"{label}.release.{key} 必须为 true")
legacy_rules = project.get("legacy_rules")
if not isinstance(legacy_rules, list):
errors.append(f"{label}.legacy_rules 必须是数组")
else:
for legacy_index, rule in enumerate(legacy_rules):
item_label = f"{label}.legacy_rules[{legacy_index}]"
if not isinstance(rule, dict):
errors.append(f"{item_label} 必须是对象")
continue
for key in ("name", "reason", "evidence"):
require_text(rule, key, item_label, errors)
if rule.get("disposition") not in VALID_LEGACY_DISPOSITIONS:
errors.append(f"{item_label}.disposition 不合法")
if not isinstance(rule.get("enabled"), bool):
errors.append(f"{item_label}.enabled 必须是布尔值")
validate_controls(project.get("controls"), f"{label}.controls", errors)
def validate(data: dict[str, Any]) -> list[str]:
errors: list[str] = []
if data.get("schema_version") != 1:
errors.append("schema_version 必须为 1")
if data.get("flow_model") != "oneos_delivery":
errors.append("flow_model 必须为 oneos_delivery")
for key in ("organization", "work_item_type"):
require_text(data, key, "profile", errors)
if data.get("target_lifecycle") != TARGET_LIFECYCLE:
errors.append("target_lifecycle 必须与OneOS终态16状态顺序一致")
labels = data.get("task_labels")
if not isinstance(labels, list) or not REQUIRED_TASK_LABELS.issubset(set(labels)):
errors.append("task_labels 必须包含:交付、开发、测试、发版")
policies = data.get("policies")
if not isinstance(policies, dict):
errors.append("policies 必须是对象")
else:
true_keys = (
"require_formal_relations", "require_current_state_condition",
"require_nonzero_development_tasks",
"require_signed_timestamped_replay_protected_callbacks",
)
false_keys = ("allow_automatic_final_close_without_acceptance", "test_success_is_production_release")
for key in true_keys:
if policies.get(key) is not True:
errors.append(f"policies.{key} 必须为 true")
for key in false_keys:
if policies.get(key) is not False:
errors.append(f"policies.{key} 必须为 false")
parts = policies.get("bridge_idempotency_key_components")
if not isinstance(parts, list) or not parts or not all(is_text(v) for v in parts):
errors.append("policies.bridge_idempotency_key_components 不能为空")
projects = data.get("projects")
if not isinstance(projects, list) or not projects:
errors.append("projects 至少包含一个项目")
else:
for index, project in enumerate(projects):
validate_project(project, index, errors)
sensitive = walk_sensitive_keys(data)
if sensitive:
errors.append("配置中禁止出现敏感字段:" + "".join(sensitive))
if "请填写" in json.dumps(data, ensure_ascii=False):
errors.append("仍存在“请填写”占位符")
return errors
def render(data: dict[str, Any]) -> str:
lines = [
"# OneOS云效终态交付模型执行计划", "",
f"- 组织:{data['organization']}",
f"- 工作项类型:{data['work_item_type']}",
f"- 项目数:{len(data['projects'])}",
"- 完整性口径每项目48项Y/A/测试/缺陷/集成/旧规则控制。",
"- 安全边界:不修改生产流水线;发布完成后保留产品验收门禁。", "",
]
for project in data["projects"]:
missing_statuses = [s for s in TARGET_LIFECYCLE if s not in project["requirement_statuses_observed"]]
lines.extend([
f"## 项目:{project['name']}", "",
f"- 迁移阶段:{project['migration_phase']}",
f"- 任务工作流方案:{project['task_workflow_mode']}",
f"- 任务身份方式:{project['task_identity_mode']}",
f"- 原生规则可过滤关联任务身份:{'' if project['native_rule_can_filter_related_task_identity'] else ''}",
f"- 缺少目标状态:{''.join(missing_statuses) if missing_statuses else ''}", "",
"### 旧规则处置", "",
"| 规则 | 处置 | 启用 | 原因 | 证据 |", "|---|---|---|---|---|",
])
for rule in project["legacy_rules"]:
lines.append(
f"| {rule['name']} | {rule['disposition']} | {'' if rule['enabled'] else ''} | "
f"{rule['reason']} | {rule['evidence']} |"
)
lines.extend([
"", "### 48项控制台账", "",
"| ID | 方式 | 启用 | 负责人 | 回退方案 | 证据 |", "|---|---|---|---|---|---|",
])
for control in sorted(project["controls"], key=lambda item: item["id"]):
lines.append(
f"| {control['id']} | {control['mode']} | {'' if control['enabled'] else ''} | "
f"{control['owner']} | {control['fallback']} | {control['evidence']} |"
)
lines.extend([
"", "### 迁移门禁", "",
"- [ ] 目标状态与流转边已补齐。",
"- [ ] 主任务可可靠识别或已明确交桥接。",
"- [ ] 多仓库需求与开发任务均正式关联分支/MR。",
"- [ ] Testhub按需求分包且缺陷复测闭环。",
"- [ ] test、生产发布和产品验收证据分离。",
"- [ ] L01、L02已停用旧规则已有备份和回滚。", "",
])
return "\n".join(lines)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
subparsers = parser.add_subparsers(dest="command", required=True)
validate_parser = subparsers.add_parser("validate")
validate_parser.add_argument("profile", type=Path)
render_parser = subparsers.add_parser("render")
render_parser.add_argument("profile", type=Path)
render_parser.add_argument("--output", required=True, type=Path)
args = parser.parse_args()
try:
with args.profile.open("r", encoding="utf-8-sig") as handle:
data = json.load(handle)
if not isinstance(data, dict):
raise ValueError("配置根节点必须是JSON对象")
errors = validate(data)
except (OSError, json.JSONDecodeError, ValueError) as error:
print(f"配置读取失败:{error}", file=sys.stderr)
return 2
if errors:
for error in errors:
print(f"[错误] {error}", file=sys.stderr)
return 1
if args.command == "validate":
print(f"[通过] OneOS配置有效{len(data['projects'])}个项目每项目48项控制。")
return 0
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(render(data), encoding="utf-8")
print(f"[完成] 已生成执行计划:{args.output}")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -1,536 +0,0 @@
#!/usr/bin/env python3
"""Validate a project-scoped Yunxiao lifecycle profile and render an execution plan."""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from typing import Any
REQUIRED_LABELS = {"分析", "设计", "开发", "测试"}
REQUIRED_RULE_IDS = {f"R{index:02d}" for index in range(1, 13)}
REQUIRED_TASK_RULE_IDS = {f"TK{index:02d}" for index in range(1, 9)}
REQUIRED_CONTROL_IDS = {
*REQUIRED_RULE_IDS,
*REQUIRED_TASK_RULE_IDS,
*(f"TC{index:02d}" for index in range(1, 4)),
*(f"DF{index:02d}" for index in range(1, 4)),
*(f"CI{index:02d}" for index in range(1, 4)),
"L01",
"L02",
}
VALID_MODES = {
"manual",
"native_rule",
"integration_bridge",
"disabled_legacy",
"not_supported",
}
VALID_RELEASE_EVIDENCE_MODES = {
"native_release_change",
"pipeline_callback",
"manual_release_confirmation",
}
SENSITIVE_FRAGMENTS = (
"password",
"passwd",
"secret",
"token",
"cookie",
"credential",
"private_key",
"otp",
"密码",
"密钥",
)
def load_profile(path: Path) -> dict[str, Any]:
with path.open("r", encoding="utf-8-sig") as handle:
data = json.load(handle)
if not isinstance(data, dict):
raise ValueError("配置根节点必须是 JSON 对象")
return data
def is_text(value: Any) -> bool:
return isinstance(value, str) and bool(value.strip())
def require_text(container: dict[str, Any], key: str, label: str, errors: list[str]) -> None:
if not is_text(container.get(key)):
errors.append(f"{label}.{key} 不能为空")
def walk_sensitive_keys(value: Any, prefix: str = "") -> list[str]:
found: list[str] = []
if isinstance(value, dict):
for key, nested in value.items():
current = f"{prefix}.{key}" if prefix else str(key)
lower = str(key).lower()
if any(fragment in lower for fragment in SENSITIVE_FRAGMENTS):
found.append(current)
found.extend(walk_sensitive_keys(nested, current))
elif isinstance(value, list):
for index, nested in enumerate(value):
found.extend(walk_sensitive_keys(nested, f"{prefix}[{index}]"))
return found
def validate_control_list(
controls: Any, label: str, errors: list[str]
) -> None:
if not isinstance(controls, list):
errors.append(f"{label} 必须是数组")
return
seen: set[str] = set()
for index, control in enumerate(controls):
item_label = f"{label}[{index}]"
if not isinstance(control, dict):
errors.append(f"{item_label} 必须是对象")
continue
control_id = control.get("id")
if not is_text(control_id):
errors.append(f"{item_label}.id 不能为空")
continue
if control_id in seen:
errors.append(f"{label} 控制项重复:{control_id}")
seen.add(control_id)
if control_id not in REQUIRED_CONTROL_IDS:
errors.append(f"{label} 未知控制项:{control_id}")
mode = control.get("mode")
if mode not in VALID_MODES:
errors.append(f"{item_label}.mode 不合法")
if not isinstance(control.get("enabled"), bool):
errors.append(f"{item_label}.enabled 必须是布尔值")
for key in ("evidence", "owner", "fallback"):
require_text(control, key, item_label, errors)
if mode in {"disabled_legacy", "not_supported"} and control.get("enabled") is not False:
errors.append(f"{item_label}{mode} 模式要求 enabled=false")
if control_id in {"L01", "L02"} and mode not in {
"disabled_legacy",
"native_rule",
"manual",
}:
errors.append(f"{item_label} 必须明确为停用旧规则、获批原生规则或人工处置")
missing = sorted(REQUIRED_CONTROL_IDS - seen)
if missing:
errors.append(f"{label} 缺少控制项:" + "".join(missing))
def validate_rule_instances(
rules: Any, lifecycle: list[str], label: str, errors: list[str]
) -> None:
if not isinstance(rules, list):
errors.append(f"{label} 必须是数组")
return
seen: set[str] = set()
orders: set[int] = set()
expected = {
f"R{index + 1:02d}": (lifecycle[index], lifecycle[index + 1])
for index in range(12)
}
for index, rule in enumerate(rules):
item_label = f"{label}[{index}]"
if not isinstance(rule, dict):
errors.append(f"{item_label} 必须是对象")
continue
rule_id = rule.get("id")
if not is_text(rule_id):
errors.append(f"{item_label}.id 不能为空")
continue
if rule_id in seen:
errors.append(f"{label} 规则实例重复:{rule_id}")
seen.add(rule_id)
if rule_id not in REQUIRED_RULE_IDS:
errors.append(f"{label} 未知规则实例:{rule_id}")
mode = rule.get("mode")
if mode not in {"manual", "native_rule", "integration_bridge", "not_supported"}:
errors.append(f"{item_label}.mode 不合法")
for key in ("actual_rule_name", "trigger", "source_status", "target_status", "action", "evidence"):
require_text(rule, key, item_label, errors)
conditions = rule.get("conditions")
if not isinstance(conditions, list) or not conditions or not all(is_text(v) for v in conditions):
errors.append(f"{item_label}.conditions 必须是非空文本数组")
order = rule.get("order")
if not isinstance(order, int) or order < 1:
errors.append(f"{item_label}.order 必须是正整数")
elif order in orders:
errors.append(f"{label} 规则顺序重复:{order}")
else:
orders.add(order)
if not isinstance(rule.get("enabled"), bool):
errors.append(f"{item_label}.enabled 必须是布尔值")
if rule.get("has_current_state_condition") is not True:
errors.append(f"{item_label}.has_current_state_condition 必须为 true")
if rule_id in expected:
expected_source, expected_target = expected[rule_id]
if rule.get("source_status") != expected_source:
errors.append(f"{item_label}.source_status 应为 {expected_source}")
if rule.get("target_status") != expected_target:
errors.append(f"{item_label}.target_status 应为 {expected_target}")
missing = sorted(REQUIRED_RULE_IDS - seen)
if missing:
errors.append(f"{label} 缺少规则实例:" + "".join(missing))
def validate_task_rule_instances(rules: Any, label: str, errors: list[str]) -> None:
if not isinstance(rules, list):
errors.append(f"{label} 必须是数组")
return
seen: set[str] = set()
orders: set[int] = set()
for index, rule in enumerate(rules):
item_label = f"{label}[{index}]"
if not isinstance(rule, dict):
errors.append(f"{item_label} 必须是对象")
continue
rule_id = rule.get("id")
if not is_text(rule_id):
errors.append(f"{item_label}.id 不能为空")
continue
if rule_id in seen:
errors.append(f"{label} 规则实例重复:{rule_id}")
seen.add(rule_id)
if rule_id not in REQUIRED_TASK_RULE_IDS:
errors.append(f"{label} 未知任务规则实例:{rule_id}")
if rule.get("mode") not in {"manual", "native_rule", "integration_bridge", "not_supported"}:
errors.append(f"{item_label}.mode 不合法")
for key in ("actual_rule_name", "trigger", "scope", "source_state", "evidence"):
require_text(rule, key, item_label, errors)
for key in ("conditions", "actions"):
values = rule.get(key)
if not isinstance(values, list) or not values or not all(is_text(value) for value in values):
errors.append(f"{item_label}.{key} 必须是非空文本数组")
order = rule.get("order")
if not isinstance(order, int) or order < 1:
errors.append(f"{item_label}.order 必须是正整数")
elif order in orders:
errors.append(f"{label} 规则顺序重复:{order}")
else:
orders.add(order)
if not isinstance(rule.get("enabled"), bool):
errors.append(f"{item_label}.enabled 必须是布尔值")
missing = sorted(REQUIRED_TASK_RULE_IDS - seen)
if missing:
errors.append(f"{label} 缺少任务规则实例:" + "".join(missing))
def validate_project(
project: Any, index: int, lifecycle: list[str], errors: list[str]
) -> None:
label = f"projects[{index}]"
if not isinstance(project, dict):
errors.append(f"{label} 必须是对象")
return
for key in ("name", "work_item_type", "release_status", "final_status"):
require_text(project, key, label, errors)
if project.get("release_status") != lifecycle[11]:
errors.append(f"{label}.release_status 必须与 lifecycle[11] 一致")
if project.get("final_status") != lifecycle[12]:
errors.append(f"{label}.final_status 必须与 lifecycle[12] 一致")
labels = project.get("labels_observed")
if not isinstance(labels, list) or not REQUIRED_LABELS.issubset(set(labels)):
errors.append(f"{label}.labels_observed 必须包含:分析、设计、开发、测试")
repositories = project.get("repositories")
if not isinstance(repositories, list) or not repositories:
errors.append(f"{label}.repositories 至少包含一个仓库")
else:
for repo_index, repo in enumerate(repositories):
repo_label = f"{label}.repositories[{repo_index}]"
if not isinstance(repo, dict):
errors.append(f"{repo_label} 必须是对象")
continue
for key in ("name", "role", "integration_branch", "evidence"):
require_text(repo, key, repo_label, errors)
if repo.get("integration_branch") not in {"dev", "develop"}:
errors.append(f"{repo_label}.integration_branch 只能是实际存在的 dev/develop")
for key in ("codeup_integrated", "required_for_mr_gate"):
if not isinstance(repo.get(key), bool):
errors.append(f"{repo_label}.{key} 必须是布尔值")
pipeline = project.get("test_pipeline")
if not isinstance(pipeline, dict):
errors.append(f"{label}.test_pipeline 必须是对象")
else:
for key in ("name", "environment", "evidence"):
require_text(pipeline, key, f"{label}.test_pipeline", errors)
for key in (
"is_clone_for_callback_poc",
"original_pipeline_unchanged",
"docker_success_callback_enabled",
):
if not isinstance(pipeline.get(key), bool):
errors.append(f"{label}.test_pipeline.{key} 必须是布尔值")
security = pipeline.get("callback_security")
if not isinstance(security, dict):
errors.append(f"{label}.test_pipeline.callback_security 必须是对象")
else:
security_keys = (
"signed",
"timestamp_checked",
"replay_protected",
"idempotent_by_execution_id",
"failure_retry_tested",
)
for key in security_keys:
if not isinstance(security.get(key), bool):
errors.append(f"{label}.test_pipeline.callback_security.{key} 必须是布尔值")
if pipeline.get("docker_success_callback_enabled") is True:
if pipeline.get("is_clone_for_callback_poc") is not True:
errors.append(f"{label} 启用回调时必须使用test流水线副本")
if pipeline.get("original_pipeline_unchanged") is not True:
errors.append(f"{label} 启用回调时必须保持原流水线不变")
if any(security.get(key) is not True for key in security_keys):
errors.append(f"{label} 启用回调时必须完成全部安全与重试验证")
release = project.get("release_evidence")
if not isinstance(release, dict):
errors.append(f"{label}.release_evidence 必须是对象")
else:
if release.get("mode") not in VALID_RELEASE_EVIDENCE_MODES:
errors.append(f"{label}.release_evidence.mode 不合法")
for key in ("target_environment", "evidence"):
require_text(release, key, f"{label}.release_evidence", errors)
if release.get("test_success_is_production_release") is not False:
errors.append(f"{label}.release_evidence.test_success_is_production_release 必须为 false")
test_plan = project.get("test_plan")
if not isinstance(test_plan, dict):
errors.append(f"{label}.test_plan 必须是对象")
else:
for key in ("name", "evidence"):
require_text(test_plan, key, f"{label}.test_plan", errors)
if not isinstance(test_plan.get("requirement_formally_related"), bool):
errors.append(f"{label}.test_plan.requirement_formally_related 必须是布尔值")
states = test_plan.get("case_states_observed")
if not isinstance(states, list) or not states or not all(is_text(v) for v in states):
errors.append(f"{label}.test_plan.case_states_observed 必须是非空文本数组")
defect = project.get("defect_workflow")
if not isinstance(defect, dict):
errors.append(f"{label}.defect_workflow 必须是对象")
else:
for key in ("fixed_status", "closed_status", "reopen_status", "evidence"):
require_text(defect, key, f"{label}.defect_workflow", errors)
if defect.get("fixed_is_terminal") is not False:
errors.append(f"{label}.defect_workflow.fixed_is_terminal 必须为 false")
if defect.get("tester_retest_required") is not True:
errors.append(f"{label}.defect_workflow.tester_retest_required 必须为 true")
validate_rule_instances(project.get("rule_instances"), lifecycle, f"{label}.rule_instances", errors)
validate_task_rule_instances(
project.get("task_rule_instances"), f"{label}.task_rule_instances", errors
)
validate_control_list(project.get("control_coverage"), f"{label}.control_coverage", errors)
if not isinstance(project.get("adjunct_automations"), list):
errors.append(f"{label}.adjunct_automations 必须是数组,可为空")
def validate(data: dict[str, Any]) -> list[str]:
errors: list[str] = []
if data.get("schema_version") != 3:
errors.append("schema_version 必须为 3旧版台账不包含阶段任务闭环")
for key in ("organization", "work_item_type"):
require_text(data, key, "profile", errors)
lifecycle = data.get("lifecycle")
if not isinstance(lifecycle, list) or len(lifecycle) != 13 or not all(is_text(v) for v in lifecycle):
errors.append("lifecycle 必须包含 13 个非空有序状态")
lifecycle = [str(index) for index in range(13)]
elif len(set(lifecycle)) != len(lifecycle):
errors.append("lifecycle 状态名称不能重复")
labels = data.get("requirement_labels")
if not isinstance(labels, list) or not REQUIRED_LABELS.issubset(set(labels)):
errors.append("requirement_labels 必须包含:分析、设计、开发、测试")
policy = data.get("automation_policy")
if not isinstance(policy, dict):
errors.append("automation_policy 必须是对象")
else:
for key in ("require_current_state_condition", "inspect_rule_order_and_cascades"):
if policy.get(key) is not True:
errors.append(f"automation_policy.{key} 必须为 true")
for key in ("allow_automatic_final_close_without_acceptance", "zero_related_items_are_complete"):
if policy.get(key) is not False:
errors.append(f"automation_policy.{key} 必须为 false")
events = policy.get("development_start_event_candidates")
if not isinstance(events, list) or not events or not all(is_text(v) for v in events):
errors.append("automation_policy.development_start_event_candidates 不能为空")
if policy.get("require_code_assets_linked_to_requirement_and_development_task") is not True:
errors.append(
"automation_policy.require_code_assets_linked_to_requirement_and_development_task 必须为 true"
)
idempotency = policy.get("stage_task_creation_idempotency_key_components")
if not isinstance(idempotency, list) or not idempotency or not all(is_text(v) for v in idempotency):
errors.append("automation_policy.stage_task_creation_idempotency_key_components 不能为空")
test_policy = data.get("test_closure_policy")
if not isinstance(test_policy, dict):
errors.append("test_closure_policy 必须是对象")
else:
if test_policy.get("defect_fixed_is_terminal") is not False:
errors.append("test_closure_policy.defect_fixed_is_terminal 必须为 false")
if test_policy.get("require_tester_retest") is not True:
errors.append("test_closure_policy.require_tester_retest 必须为 true")
for key in ("accepted_case_states", "rejected_case_states"):
values = test_policy.get(key)
if not isinstance(values, list) or not values or not all(is_text(v) for v in values):
errors.append(f"test_closure_policy.{key} 不能为空")
projects = data.get("projects")
if not isinstance(projects, list) or not projects:
errors.append("projects 至少包含一个项目")
else:
names: set[str] = set()
for index, project in enumerate(projects):
validate_project(project, index, lifecycle, errors)
if isinstance(project, dict) and is_text(project.get("name")):
name = project["name"]
if name in names:
errors.append(f"项目名称重复:{name}")
names.add(name)
sensitive = walk_sensitive_keys(data)
if sensitive:
errors.append("配置中禁止出现敏感字段:" + "".join(sensitive))
if "请填写" in json.dumps(data, ensure_ascii=False):
errors.append("仍存在“请填写”占位符")
return errors
def render(data: dict[str, Any]) -> str:
lines = [
"# 云效需求生命周期自动化执行计划",
"",
f"- 组织:{data['organization']}",
f"- 工作项类型:{data['work_item_type']}",
f"- 项目数:{len(data['projects'])}",
"- 完整性口径每项目12个需求规则实例、8个任务规则实例、31个闭环控制项。",
"- 安全边界:不修改现有生产流水线;不记录任何凭据或密钥。",
"",
]
for project in data["projects"]:
lines.extend([
f"## 项目:{project['name']}",
"",
f"- 发布状态:{project['release_status']}",
f"- 最终状态:{project['final_status']}",
f"- test流水线{project['test_pipeline']['name']}",
f"- 发布证据方式:{project['release_evidence']['mode']}",
"",
"### 仓库覆盖",
"",
"| 仓库 | 角色 | 集成分支 | Codeup已集成 | 纳入全部MR门禁 | 证据 |",
"|---|---|---|---|---|---|",
])
for repo in project["repositories"]:
lines.append(
f"| {repo['name']} | {repo['role']} | {repo['integration_branch']} | "
f"{'' if repo['codeup_integrated'] else ''} | "
f"{'' if repo['required_for_mr_gate'] else ''} | {repo['evidence']} |"
)
lines.extend([
"",
"### R01R12实际规则实例",
"",
"| ID | 实现 | 实际规则/门禁 | 触发 | 流转 | 条件 | 顺序 | 启用 | 证据 |",
"|---|---|---|---|---|---|---:|---|---|",
])
for rule in sorted(project["rule_instances"], key=lambda item: item["order"]):
conditions = "".join(rule["conditions"])
lines.append(
f"| {rule['id']} | {rule['mode']} | {rule['actual_rule_name']} | {rule['trigger']} | "
f"{rule['source_status']}{rule['target_status']} | {conditions} | {rule['order']} | "
f"{'' if rule['enabled'] else ''} | {rule['evidence']} |"
)
lines.extend([
"",
"### TK01TK08任务规则实例",
"",
"| ID | 实现 | 实际规则/门禁 | 触发 | 作用域 | 源状态 | 条件 | 动作 | 顺序 | 启用 | 证据 |",
"|---|---|---|---|---|---|---|---|---:|---|---|",
])
for rule in sorted(project["task_rule_instances"], key=lambda item: item["order"]):
conditions = "".join(rule["conditions"])
actions = "".join(rule["actions"])
lines.append(
f"| {rule['id']} | {rule['mode']} | {rule['actual_rule_name']} | {rule['trigger']} | "
f"{rule['scope']} | {rule['source_state']} | {conditions} | {actions} | {rule['order']} | "
f"{'' if rule['enabled'] else ''} | {rule['evidence']} |"
)
lines.extend([
"",
"### 31项完整性台账",
"",
"| 控制ID | 实现方式 | 启用 | 观察证据 | 负责人 | 回退方案 |",
"|---|---|---|---|---|---|",
])
for control in sorted(project["control_coverage"], key=lambda item: item["id"]):
lines.append(
f"| {control['id']} | {control['mode']} | {'' if control['enabled'] else ''} | "
f"{control['evidence']} | {control['owner']} | {control['fallback']} |"
)
adjunct = project["adjunct_automations"]
lines.extend([
"",
"### 范围外通用自动化盘点",
"",
"- " + ("".join(map(str, adjunct)) if adjunct else "未纳入如需通知、自动指派、SLA、字段同步等应单独授权和设计。"),
"",
])
lines.extend([
"## 执行检查",
"",
"- [ ] 两个或多个项目的规则实例、控制台账和证据已分别填写。",
"- [ ] 已逐条读取真实触发配置、规则顺序、启用状态和执行账号。",
"- [ ] 已检查后继规则、重复规则和跨阶段连锁流转。",
"- [ ] 已验证失败用例、缺陷已修复、复测通过/失败时双方状态一致。",
"- [ ] 已逐仓库确认真实dev/develop分支、正式关联和全部MR门禁。",
"- [ ] 已区分test部署、生产发布、发布变更和业务验收。",
"- [ ] 已执行正向、负向、异步、多仓库、失败重试和旧规则连锁测试。",
"",
])
return "\n".join(lines)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
subparsers = parser.add_subparsers(dest="command", required=True)
validate_parser = subparsers.add_parser("validate", help="验证项目配置")
validate_parser.add_argument("profile", type=Path)
render_parser = subparsers.add_parser("render", help="生成 Markdown 执行计划")
render_parser.add_argument("profile", type=Path)
render_parser.add_argument("--output", required=True, type=Path)
args = parser.parse_args()
try:
data = load_profile(args.profile)
errors = validate(data)
except (OSError, json.JSONDecodeError, ValueError) as error:
print(f"配置读取失败:{error}", file=sys.stderr)
return 2
if errors:
for error in errors:
print(f"[错误] {error}", file=sys.stderr)
return 1
if args.command == "validate":
print(
f"[通过] 配置有效:{len(data['projects'])} 个项目;"
"每项目12个需求规则实例、8个任务规则实例、31个闭环控制项。"
)
return 0
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(render(data), encoding="utf-8")
print(f"[完成] 已生成执行计划:{args.output}")
return 0
if __name__ == "__main__":
raise SystemExit(main())