create-yss-spec 3.3.7 → 3.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -13
- package/package.json +1 -1
- package/template/.agents/skills/.strategic-design-skills-manifest.json +2 -2
- package/template/.agents/skills/implementation-repo-onboarding/SKILL.md +2 -2
- package/template/.agents/skills/yss-application/SKILL.md +1 -1
- package/template/.agents/skills/yss-application/references/profiles/existing-domain-driven-maven.md +5 -0
- package/template/.agents/skills/yss-application/references/profiles/existing-layered-mvc-maven.md +5 -0
- package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +2 -2
- package/template/.agents/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +4 -0
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +6 -1
- package/template/.agents/skills/yss-prototype-stage/SKILL.md +10 -1
- package/template/.agents/skills/yss-technical-design/SKILL.md +2 -0
- package/template/.agents/skills/yss-technical-design/references/engineering-design.schema.json +224 -0
- package/template/.agents/skills/yss-technical-design/references/technical-design-common.schema.json +6 -0
- package/template/.agents/skills/yss-technical-design/references/technical-design.schema.json +288 -10
- package/template/.agents/skills/yss-technical-design/scripts/engineering-design.mjs +30 -0
- package/template/.agents/skills/yss-technical-design/scripts/generate-schema.mjs +2 -1
- package/template/.agents/skills/yss-technical-design/scripts/validate-technical-design.mjs +20 -8
- package/template/.agents/skills/yss-technical-design/tests/engineering-scenarios.mjs +12 -0
- package/template/.agents/skills/yss-web-controller/SKILL.md +1 -1
- package/template/.agents/skills/yss-web-controller/references/profiles/existing-domain-driven-maven.md +5 -0
- package/template/.agents/skills/yss-web-controller/references/profiles/existing-layered-mvc-maven.md +5 -0
- package/template/.codex/skills/implementation-repo-onboarding/SKILL.md +2 -2
- package/template/.codex/skills/yss-application/SKILL.md +1 -1
- package/template/.codex/skills/yss-application/references/profiles/existing-domain-driven-maven.md +5 -0
- package/template/.codex/skills/yss-application/references/profiles/existing-layered-mvc-maven.md +5 -0
- package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +2 -2
- package/template/.codex/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +4 -0
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +6 -1
- package/template/.codex/skills/yss-prototype-stage/SKILL.md +10 -1
- package/template/.codex/skills/yss-technical-design/SKILL.md +2 -0
- package/template/.codex/skills/yss-technical-design/references/engineering-design.schema.json +224 -0
- package/template/.codex/skills/yss-technical-design/references/technical-design-common.schema.json +6 -0
- package/template/.codex/skills/yss-technical-design/references/technical-design.schema.json +288 -10
- package/template/.codex/skills/yss-technical-design/scripts/engineering-design.mjs +30 -0
- package/template/.codex/skills/yss-technical-design/scripts/generate-schema.mjs +2 -1
- package/template/.codex/skills/yss-technical-design/scripts/validate-technical-design.mjs +20 -8
- package/template/.codex/skills/yss-technical-design/tests/engineering-scenarios.mjs +12 -0
- package/template/.codex/skills/yss-web-controller/SKILL.md +1 -1
- package/template/.codex/skills/yss-web-controller/references/profiles/existing-domain-driven-maven.md +5 -0
- package/template/.codex/skills/yss-web-controller/references/profiles/existing-layered-mvc-maven.md +5 -0
- package/template/.cursor/skills/implementation-repo-onboarding/SKILL.md +2 -2
- package/template/.cursor/skills/yss-application/SKILL.md +1 -1
- package/template/.cursor/skills/yss-application/references/profiles/existing-domain-driven-maven.md +5 -0
- package/template/.cursor/skills/yss-application/references/profiles/existing-layered-mvc-maven.md +5 -0
- package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +2 -2
- package/template/.cursor/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +4 -0
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +6 -1
- package/template/.cursor/skills/yss-prototype-stage/SKILL.md +10 -1
- package/template/.cursor/skills/yss-technical-design/SKILL.md +2 -0
- package/template/.cursor/skills/yss-technical-design/references/engineering-design.schema.json +224 -0
- package/template/.cursor/skills/yss-technical-design/references/technical-design-common.schema.json +6 -0
- package/template/.cursor/skills/yss-technical-design/references/technical-design.schema.json +288 -10
- package/template/.cursor/skills/yss-technical-design/scripts/engineering-design.mjs +30 -0
- package/template/.cursor/skills/yss-technical-design/scripts/generate-schema.mjs +2 -1
- package/template/.cursor/skills/yss-technical-design/scripts/validate-technical-design.mjs +20 -8
- package/template/.cursor/skills/yss-technical-design/tests/engineering-scenarios.mjs +12 -0
- package/template/.cursor/skills/yss-web-controller/SKILL.md +1 -1
- package/template/.cursor/skills/yss-web-controller/references/profiles/existing-domain-driven-maven.md +5 -0
- package/template/.cursor/skills/yss-web-controller/references/profiles/existing-layered-mvc-maven.md +5 -0
- package/template/.pi/skills/implementation-repo-onboarding/SKILL.md +2 -2
- package/template/.pi/skills/yss-application/SKILL.md +1 -1
- package/template/.pi/skills/yss-application/references/profiles/existing-domain-driven-maven.md +5 -0
- package/template/.pi/skills/yss-application/references/profiles/existing-layered-mvc-maven.md +5 -0
- package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +2 -2
- package/template/.pi/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +4 -0
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +6 -1
- package/template/.pi/skills/yss-prototype-stage/SKILL.md +10 -1
- package/template/.pi/skills/yss-technical-design/SKILL.md +2 -0
- package/template/.pi/skills/yss-technical-design/references/engineering-design.schema.json +224 -0
- package/template/.pi/skills/yss-technical-design/references/technical-design-common.schema.json +6 -0
- package/template/.pi/skills/yss-technical-design/references/technical-design.schema.json +288 -10
- package/template/.pi/skills/yss-technical-design/scripts/engineering-design.mjs +30 -0
- package/template/.pi/skills/yss-technical-design/scripts/generate-schema.mjs +2 -1
- package/template/.pi/skills/yss-technical-design/scripts/validate-technical-design.mjs +20 -8
- package/template/.pi/skills/yss-technical-design/tests/engineering-scenarios.mjs +12 -0
- package/template/.pi/skills/yss-web-controller/SKILL.md +1 -1
- package/template/.pi/skills/yss-web-controller/references/profiles/existing-domain-driven-maven.md +5 -0
- package/template/.pi/skills/yss-web-controller/references/profiles/existing-layered-mvc-maven.md +5 -0
- package/template/README.md +4 -6
- package/template/docs/agents/backend-architecture-profiles.md +4 -0
- package/template/docs/agents/yss-skill-registry.yaml +13 -0
- package/template/docs/design/templates/prototype-confirmation-template.md +2 -2
- package/template/docs/design/templates/prototype-review-checklist.md +2 -2
- package/template/docs/plan/templates/market-analysis-template.md +3 -3
- package/template/docs/plan/templates/user-pain-points-template.md +3 -3
- package/template/docs/process/delivery-preflight.md +72 -0
- package/template/docs/process/document-writing.md +5 -1
- package/template/docs/process/existing-backend-architecture.md +31 -0
- package/template/docs/process/existing-ui-baseline.md +40 -0
- package/template/docs/process/frontend-backend-delivery.md +19 -6
- package/template/docs/process/implementation-repo-integration.md +6 -0
- package/template/docs/process/schemas/backend-architecture-identity.schema.json +111 -14
- package/template/docs/process/schemas/delivery-preflight-input.schema.json +158 -0
- package/template/docs/process/schemas/delivery-preflight-result.schema.json +159 -0
- package/template/docs/process/schemas/digital-human-task-package.schema.json +1 -1
- package/template/docs/process/schemas/existing-ui-baseline.schema.json +365 -0
- package/template/docs/process/schemas/frontend-delivery-acceptance-v3.schema.json +308 -0
- package/template/docs/process/schemas/frontend-strategic-preflight-v2.schema.json +114 -0
- package/template/docs/process/schemas/strategic-design-handoff-v5.schema.json +932 -0
- package/template/docs/process/schemas/strategic-handoff-export-v2.schema.json +378 -0
- package/template/docs/process/strategic-handoff-package.md +21 -13
- package/template/docs/user-guide//346/212/200/346/234/257/350/256/276/350/256/241/347/224/250/346/210/267/346/214/207/345/215/227.md +43 -0
- package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +83 -67
- package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214/347/264/242/345/274/225.md +9 -10
- package/template/docs/user-guide//350/256/276/345/244/207/345/200/237/347/224/250/350/264/257/347/251/277/346/241/210/344/276/213.md +12 -9
- package/template/scripts/backend-delivery +20 -4
- package/template/scripts/lib/approved-execution-context.mjs +106 -0
- package/template/scripts/lib/backend-architecture.mjs +12 -0
- package/template/scripts/lib/backend-delivery.mjs +10 -6
- package/template/scripts/lib/delivery-preflight.mjs +238 -0
- package/template/scripts/lib/existing-backend-architecture.mjs +139 -0
- package/template/scripts/lib/existing-ui-baseline.mjs +84 -0
- package/template/scripts/lib/frontend-delivery.mjs +23 -15
- package/template/scripts/lib/implementation-contract-compiler.mjs +19 -5
- package/template/scripts/lib/json-schema.mjs +19 -4
- package/template/scripts/lib/profile-skill-sync.mjs +26 -0
- package/template/scripts/lib/strategic-handoff-consumption.mjs +6 -5
- package/template/scripts/lib/strategic-handoff-design-targets.mjs +2 -3
- package/template/scripts/lib/strategic-handoff-io.mjs +10 -0
- package/template/scripts/lib/strategic-handoff.mjs +47 -29
- package/template/scripts/lib/task-package.mjs +11 -3
- package/template/scripts/lib/technical-design-boundary.mjs +9 -1
- package/template/scripts/lib/ui-baseline.mjs +26 -0
- package/template/scripts/lib/user-decision.mjs +4 -1
- package/template/scripts/preflight-delivery +14 -0
- package/template/scripts/strategic-handoff +19 -4
- package/template/scripts/sync-profile-skills +4 -5
- package/template/skills-lock.json +15 -15
- package/template.snapshot.json +3 -3
- package/template/docs/user-guide//346/210/230/346/234/257/350/256/276/350/256/241/345/255/220/351/241/271/347/233/256/347/224/250/346/210/267/346/211/213/345/206/214.md +0 -35
|
@@ -1,114 +1,130 @@
|
|
|
1
1
|
# YSS 用户手册
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
本手册帮助项目负责人选择模板、创建或接管项目,并判断 Agent 何时可以继续工作。本仓是 `template-source`;真实业务材料只能写入由 CLI 生成或接管的 `project-instance`。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 选择项目家族
|
|
6
6
|
|
|
7
|
-
|
|
|
7
|
+
| 你的责任 | 模板与 CLI | 本地终点 |
|
|
8
8
|
|---|---|---|
|
|
9
|
-
|
|
|
10
|
-
|
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
| 接收战略及后端交付,承担前端 | 前端模板 `yss-harness-frontend-agent` | `create-yss-harness-frontend`:init、attach、sync(首版候选) |
|
|
9
|
+
| 统一管理从业务问题到实现、验证和发布 | `yss-spec-project-template` / `create-yss-spec` | 完整业务切片验收 |
|
|
10
|
+
| 澄清业务、形成 Spec、页面方案和战略交接 | `yss-harness-design-agent` / `create-yss-harness-design` | Strategic Design Handoff |
|
|
11
|
+
| 设计并实现后端、冻结接口并输出后端交付 | `yss-harness-backend-agent` / `create-yss-harness-backend` | Backend Delivery |
|
|
12
|
+
| 联合接收战略和后端交付、实现并验收前端 | `yss-harness-frontend-agent` / `create-yss-harness-frontend` | Frontend Acceptance |
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
专职路线通常按“战略 → 后端 → 前端 → 统一业务验收”接力。每个子项目只确认自己的职责完成;统一管理方绑定同一战略、接口、部署和前端版本后,才能判断整个业务切片是否完成。
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
既有 `yss-harness-dev-agent` / `create-yss-harness-dev` 实例继续按其固定版本和本地 README 维护。本家族已退出当前项目选型,不自动迁移到综合、后端或前端家族,也不能通过修改 metadata 转换身份。
|
|
18
17
|
|
|
19
|
-
##
|
|
18
|
+
## CLI 能力与写入方式
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
先运行所用包的 `--version` 和 `--help`;源码候选版本、npm 已发布版本和实例记录的模板快照是三个不同事实。
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
| 能力 | `create-yss-spec` | 战略、后端、前端专职 CLI |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| init | 默认命令;写入新目录 | `init`;只接受不存在或空目录 |
|
|
25
|
+
| attach | 必须显式选择 `--dry-run` 或 `--apply` | 默认预览;`--apply` 写入 |
|
|
26
|
+
| sync | 默认写入;`--dry-run`、`--plan`、`--json` 只读 | 默认预览;`--apply` 写入 |
|
|
27
|
+
| diff / doctor | 支持,只读 | 支持,只读 |
|
|
28
|
+
| recover | 无独立命令;失败由事务回滚 | 默认只读诊断;`recover --apply` 恢复未完成事务 |
|
|
29
|
+
| prune | `sync --prune` | `sync --plan --prune` 预览,`sync --apply --prune` 写入 |
|
|
30
|
+
| update / upgrade | 只更新 CLI 程序 | 只更新 CLI 程序 |
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
`--prune` 只删除仍与可信旧 baseline 相同的退出分发文件。用户改过的旧文件会保留并报告;`--force` 也不能放宽删除、身份、Git、gitlink 或路径安全条件。
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
## 安装、创建与核对
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
先确认 npm 中确有需要的版本:
|
|
34
37
|
|
|
35
38
|
```sh
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
npm view create-yss-spec version
|
|
40
|
+
npm view create-yss-harness-design version
|
|
41
|
+
npm view create-yss-harness-backend version
|
|
42
|
+
npm view create-yss-harness-frontend version
|
|
38
43
|
```
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
再选择一个家族创建项目,例如:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
npm create yss-spec@latest
|
|
49
|
+
npx create-yss-harness-design@latest init --target-dir ./design-project --project-name 设备借用 --business-domain 内部设备管理
|
|
50
|
+
npx create-yss-harness-backend@latest init --target-dir ./backend-project --project-name 设备借用 --business-domain 内部设备管理
|
|
51
|
+
npx create-yss-harness-frontend@latest init --target-dir ./frontend-project --project-name 设备借用 --business-domain 内部设备管理
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`@latest` 取得 npm 已发布包,不保证等于 GitHub 当前源码。候选包必须从对应 CLI 仓库构建实际 tgz,并核对 `package.json`、`template.snapshot.json` 的 `templateCommit`、来源状态和摘要;CLI 使用包内快照,不会运行时拉取模板仓。
|
|
55
|
+
|
|
56
|
+
初始化或 attach 后检查:
|
|
41
57
|
|
|
42
|
-
|
|
58
|
+
1. `yss-project.yaml` 是 `project-instance`。
|
|
59
|
+
2. 只存在本家族 metadata,且 profile 与职责一致。
|
|
60
|
+
3. 根 `CONTEXT.md`、`AGENTS.md` 和 `docs/user-guide/用户手册索引.md` 可读。
|
|
61
|
+
4. Git 状态、实现仓登记、验证命令和回滚点符合项目实际情况。
|
|
43
62
|
|
|
44
63
|
## 第一次让 Agent 工作
|
|
45
64
|
|
|
46
|
-
|
|
65
|
+
在生成的项目实例中发送:
|
|
47
66
|
|
|
48
67
|
```text
|
|
49
|
-
请先只读检查 yss-project.yaml、根 CONTEXT.md、AGENTS.md
|
|
68
|
+
请先只读检查 yss-project.yaml、根 CONTEXT.md、AGENTS.md 和 harness-profile.yaml。
|
|
50
69
|
告诉我本仓职责、当前可信阶段、上游输入、缺失证据和下一步。
|
|
51
|
-
|
|
70
|
+
发现身份非法、输入过期或职责越界时停止并给出恢复办法;先不要写代码。
|
|
52
71
|
```
|
|
53
72
|
|
|
54
|
-
|
|
73
|
+
正确结果应说明当前事实、阻塞责任和下一动作。模板文件存在、导入成功、验证包摘要成功或 Agent 自报完成,都不能替代当前批准和 Fresh Verification。
|
|
55
74
|
|
|
56
|
-
##
|
|
75
|
+
## 用户需要确认什么
|
|
57
76
|
|
|
58
|
-
| 看到的材料 |
|
|
77
|
+
| 看到的材料 | 需要判断 | 确认后的边界 |
|
|
59
78
|
|---|---|---|
|
|
60
|
-
| 目标、范围、规则及反例 |
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
| 当前 Slice Contract |
|
|
64
|
-
| 本轮验证和发布方案 | 覆盖、风险、回滚和交付范围 |
|
|
79
|
+
| 目标、范围、规则及反例 | 业务是否正确、哪些不做 | 允许继续设计,不自动批准实现 |
|
|
80
|
+
| 页面流程、状态和视觉基线 | 成功、失败、权限与恢复是否完整 | 形成当前产品设计输入 |
|
|
81
|
+
| 架构、接口和脚手架方案 | 责任、兼容、数据和回滚是否可接受 | 完成对应工程会签 |
|
|
82
|
+
| 当前 Slice Contract | 写哪些仓库与路径、如何验收 | 门禁通过后才允许实施 |
|
|
83
|
+
| 本轮验证和发布方案 | 覆盖、风险、回滚和交付范围 | 发布与外部承诺仍需生物人 |
|
|
65
84
|
|
|
66
|
-
|
|
85
|
+
批准身份、范围和失效条件以本地 `digital-human-roles.yaml` 与 `lifecycle-registry.yaml` 为准。编译器只起草合同;`inputs-verified` 只允许继续准备计划和合同;只有当前合同获准、阻塞清除的切片才可进入 `ready-for-agent`。
|
|
67
86
|
|
|
68
|
-
##
|
|
87
|
+
## 当前工作主线
|
|
69
88
|
|
|
70
|
-
|
|
89
|
+
综合模板从分诊、Plan、Spec、产品设计、工程契约、Ticket、实现推进到验证与发布。战略模板在业务交接停止;后端模板消费批准战略并输出可核验后端交付;前端模板联合接收战略、后端、API、数据和 UI 输入后实施前端。
|
|
71
90
|
|
|
72
|
-
|
|
91
|
+
涉及交付前提时,先运行只读 `scripts/preflight-delivery`。它只验证原始输入,不初始化项目、不运行构建、不启动服务、不生成批准或收据。导出、导入和实现边界仍要重新验证当前资产。
|
|
73
92
|
|
|
74
|
-
|
|
93
|
+
完整演练见[设备借用贯穿案例](设备借用贯穿案例.md),后端技术设计见[技术设计用户指南](技术设计用户指南.md)。
|
|
75
94
|
|
|
76
|
-
##
|
|
95
|
+
## 接管、同步与恢复
|
|
77
96
|
|
|
78
|
-
|
|
97
|
+
综合 CLI 示例:
|
|
79
98
|
|
|
80
|
-
```
|
|
81
|
-
npx create-yss-spec@latest attach --target-dir . --project-name
|
|
82
|
-
npx create-yss-spec@latest attach --target-dir . --project-name
|
|
99
|
+
```sh
|
|
100
|
+
npx create-yss-spec@latest attach --target-dir . --project-name 设备借用 --business-domain 内部设备管理 --dry-run
|
|
101
|
+
npx create-yss-spec@latest attach --target-dir . --project-name 设备借用 --business-domain 内部设备管理 --apply
|
|
83
102
|
npx create-yss-spec@latest sync --target-dir . --dry-run
|
|
84
103
|
npx create-yss-spec@latest sync --target-dir .
|
|
104
|
+
npx create-yss-spec@latest sync --target-dir . --plan --prune
|
|
85
105
|
```
|
|
86
106
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
`update`/`upgrade` 更新 CLI 程序,`sync` 更新实例受管模板,两者不同。事务校验失败会回滚本轮文件写入;成功后的撤销使用自己保存的 Git 基线或备份,不用旧 CLI 强制反向同步。
|
|
90
|
-
|
|
91
|
-
战略和专职实例本次没有自动 sync/原地迁移:用同家族新目录比较受管资产,按计划迁移,重验输入和合同,保留原实例回滚。不能跨 profile 覆盖。
|
|
107
|
+
专职 CLI 示例:
|
|
92
108
|
|
|
93
|
-
|
|
109
|
+
```sh
|
|
110
|
+
npx create-yss-harness-backend@latest attach --target-dir .
|
|
111
|
+
npx create-yss-harness-backend@latest attach --target-dir . --apply
|
|
112
|
+
npx create-yss-harness-backend@latest sync --target-dir . --plan --prune
|
|
113
|
+
npx create-yss-harness-backend@latest sync --target-dir . --apply --prune
|
|
114
|
+
npx create-yss-harness-backend@latest recover --target-dir .
|
|
115
|
+
```
|
|
94
116
|
|
|
95
|
-
|
|
117
|
+
attach 用于尚未由该家族管理的普通项目;已有本家族 metadata 时使用 sync。先审阅计划,再选择写入命令。旧 repository-local 实例、未知 schema、多重或异族身份按 CLI 输出处理,不删除 metadata 伪装普通目录。
|
|
96
118
|
|
|
97
119
|
## 常见卡点
|
|
98
120
|
|
|
99
|
-
| 现象 |
|
|
121
|
+
| 现象 | 处理 |
|
|
100
122
|
|---|---|
|
|
101
|
-
| Agent
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
业务人员确认规则和页面;架构与研发落实到冻结接口、当前合同和实际实现仓;Reviewer 独立核验。运行时代码默认进入登记的独立仓,前端优先 pnpm,后端优先根 ./mvnw;缺工具时记录受控例外与实际命令。
|
|
111
|
-
|
|
112
|
-
模板维护者先读 [AGENTS.md](../../AGENTS.md) 和 [流程裁剪](../process/harness-process-tailoring.md),维护 canonical 事实与生成投影,运行分级验证。维护流程不混入用户的日常业务步骤。
|
|
113
|
-
|
|
114
|
-
各模板与 CLI 专项手册见 [用户手册索引](用户手册索引.md)。
|
|
123
|
+
| Agent 立即写代码 | 要求只读分诊,展示当前合同、允许路径和批准证据 |
|
|
124
|
+
| 包验证成功仍不能实现 | 继续完成目标词汇对账、接收、计划和合同批准 |
|
|
125
|
+
| `--force` 仍失败 | 修复身份、冲突、unsafe 路径或 gitlink,不绕过保护 |
|
|
126
|
+
| npm 包缺少新手册 | 比对 npm 版本、CLI 版本和模板 snapshot |
|
|
127
|
+
| 旧手册仍在实例 | 先用 `sync --plan --prune` 判断是否可安全清理 |
|
|
128
|
+
| 单个子项目自报完成 | 由统一管理方核对跨仓版本和端到端业务证据 |
|
|
129
|
+
|
|
130
|
+
各家族入口见[用户手册索引](用户手册索引.md)。模板维护者另读根 [AGENTS.md](../../AGENTS.md) 和[流程裁剪](../process/harness-process-tailoring.md)。
|
|
@@ -2,17 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## 第一次使用
|
|
4
4
|
|
|
5
|
-
1. [YSS 用户手册](用户手册.md)
|
|
6
|
-
2. [设备借用贯穿案例](设备借用贯穿案例.md)
|
|
7
|
-
3. [
|
|
5
|
+
1. [YSS 用户手册](用户手册.md):四个现行家族的选型、CLI、确认、同步和恢复。
|
|
6
|
+
2. [设备借用贯穿案例](设备借用贯穿案例.md):战略、后端、前端与统一验收的完整练习。
|
|
7
|
+
3. [技术设计用户指南](技术设计用户指南.md):批准战略或 Spec 如何进入 DDD / layered-mvc 技术设计和实现合同。
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 按职责进入子项目
|
|
10
10
|
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
- [前端:联合接收、页面与验收](https://github.com/iloveZzz/yss-harness-frontend-agent/blob/main/docs/user-guide/用户手册索引.md)
|
|
11
|
+
- [战略设计](https://github.com/iloveZzz/yss-harness-design-agent/blob/main/docs/user-guide/用户手册索引.md)
|
|
12
|
+
- [后端交付](https://github.com/iloveZzz/yss-harness-backend-agent/blob/main/docs/user-guide/用户手册索引.md)
|
|
13
|
+
- [前端接收与验收](https://github.com/iloveZzz/yss-harness-frontend-agent/blob/main/docs/user-guide/用户手册索引.md)
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
既有通用研发实例按其固定版本和本地 README 维护,不再作为新项目入口。生成实例通过 GitHub 链接跨项目导航,但实际操作以本地 profile、CLI `--help`、包版本和模板 snapshot 为准。
|
|
17
16
|
|
|
18
|
-
CLI
|
|
17
|
+
CLI 详解:[综合 CLI](https://github.com/iloveZzz/create-yss-spec/blob/main/docs/user-guide/create-yss-spec-cli-guide.md)、[战略 CLI](https://github.com/iloveZzz/create-yss-harness-design)、[后端 CLI](https://github.com/iloveZzz/create-yss-harness-backend)、[前端 CLI](https://github.com/iloveZzz/create-yss-harness-frontend)。组件专项见 [YSS UI MCP](yss-ui-mcp.md)。
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 内部设备借用:贯穿四个现行家族的教学案例
|
|
2
2
|
|
|
3
3
|
本文是虚构教学说明,不是已批准 Spec、真实交付包或可直接执行的产品合同。示例路径、规则和标识由学习者在独立 `project-instance` 中确认后落盘;模板源不登记这些业务词汇。
|
|
4
4
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
## 1. 选择工作组织
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
综合模板可承载从澄清到业务验收的管理资产。战略模板只负责上游方案,后端和前端模板按交付协议接力;专职路线必须登记统一管理方及独立实现仓,不把源代码复制进模板。既有通用研发实例只按原固定版本维护,不作为本案例的新建路线。
|
|
21
21
|
|
|
22
22
|
## 2. 战略方形成可交接输入
|
|
23
23
|
|
|
@@ -29,18 +29,19 @@
|
|
|
29
29
|
列出准备交接的规则、关键场景、版本、批准证据和研发待决事项。
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
用户逐项核对业务和页面。预期输出为本仓合同要求的已批准战略资产、根词汇、交接描述及证据闭包,不能只交聊天摘要。战略方不在此生成后端工程或冻结工程 API。
|
|
32
|
+
用户逐项核对业务和页面。预期输出为本仓合同要求的已批准战略资产、根词汇、交接描述及证据闭包,不能只交聊天摘要。战略方不在此生成后端工程或冻结工程 API。UI 有变化时交付已批准原型;确认无 UI 变化的既有工程使用 `existing-ui-baseline`,不能用截图把既有界面伪装成原型。
|
|
33
33
|
|
|
34
34
|
由 Agent 给出实际交接描述路径后,在战略实例执行以下命令。尖括号必须替换为真实路径,输出目录须新建;`--handoff` 是相对源实例的文件路径。
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
+
node scripts/preflight-delivery --input <战略预检输入.json> --stage export --json
|
|
37
38
|
node scripts/strategic-handoff export --source-root . --handoff <交接描述相对路径> --output <新包目录> --zip
|
|
38
39
|
node scripts/strategic-handoff verify --bundle <包目录或ZIP>
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
预检输入使用 `delivery_kind: strategic-handoff`,绑定交接描述和当前 UI 基线。预期验包输出 `result: verified` 及包摘要;缺证据或被修改的包会失败。把完整目录/ZIP 交给下游,保留版本与摘要,不手改包内文件。
|
|
42
43
|
|
|
43
|
-
## 3.
|
|
44
|
+
## 3. 后端接收
|
|
44
45
|
|
|
45
46
|
在接收实例运行:
|
|
46
47
|
|
|
@@ -52,11 +53,11 @@ node scripts/strategic-handoff import --bundle <包目录或ZIP> --target-root .
|
|
|
52
53
|
```text
|
|
53
54
|
请读取导入收据和包内规则/场景,核对本仓根 CONTEXT.md 并形成正式对账。
|
|
54
55
|
为“已批准申请领用设备”逐项登记承接、冲突和依赖。
|
|
55
|
-
|
|
56
|
+
按当前流程核对既有工程身份,准备技术设计、API Draft/Freeze 和后端 Slice Contract,
|
|
56
57
|
登记真实实现仓、验证命令和回滚点。合同获准前只准备材料,不写代码。
|
|
57
58
|
```
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
预期保存导入收据、目标词汇对账、规则/场景承接与当前合同;导入成功不会自动批准这些资产。既有 Java/Maven 工程需要 repository registration、engineering baseline 和 observation manifest 三份当前原始证据。设备占用竞争应落实到设计与可执行测试,不能只在页面禁用按钮;API 变化回到冻结流程。
|
|
60
61
|
|
|
61
62
|
## 4. 后端交付当前切片
|
|
62
63
|
|
|
@@ -70,11 +71,12 @@ node scripts/strategic-handoff import --bundle <包目录或ZIP> --target-root .
|
|
|
70
71
|
在后端实例执行(交付描述已由实际证据形成):
|
|
71
72
|
|
|
72
73
|
```bash
|
|
74
|
+
node scripts/preflight-delivery --input <后端预检输入.json> --stage export --json
|
|
73
75
|
node scripts/backend-delivery export --source-root . --delivery <交付描述相对路径> --output <新交付包目录> --zip
|
|
74
76
|
node scripts/backend-delivery verify --bundle <交付包目录或ZIP>
|
|
75
77
|
```
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
后端预检输入使用 `delivery_kind: backend-delivery`,绑定工程身份、技术设计、冻结接口、批准合同、实际制品、部署证据和后端交付源记录。预期 `verified`,但离线验包不能证明环境当前可用。交付不包含账号密码;实际 API 和版本探测由已登记环境提供。
|
|
78
80
|
|
|
79
81
|
## 5. 前端联合接收与准备
|
|
80
82
|
|
|
@@ -82,6 +84,7 @@ node scripts/backend-delivery verify --bundle <交付包目录或ZIP>
|
|
|
82
84
|
|
|
83
85
|
```bash
|
|
84
86
|
node scripts/backend-delivery import --bundle <交付包目录或ZIP> --target-root .
|
|
87
|
+
node scripts/preflight-delivery --input <前端接收预检输入.json> --stage accept --json
|
|
85
88
|
```
|
|
86
89
|
|
|
87
90
|
战略快照随交付链导入,后端包与战略包分别验证。导入产生接收草稿;核对目标词汇、规则/场景、接口和视觉用例后才能形成正式接收记录。
|
|
@@ -99,7 +102,7 @@ node scripts/backend-delivery import --bundle <交付包目录或ZIP> --target-r
|
|
|
99
102
|
node scripts/verify-frontend-delivery --root . --slice <切片ID> <接收记录相对路径>
|
|
100
103
|
```
|
|
101
104
|
|
|
102
|
-
成功是 `inputs-verified` 且 `ready_for_agent: false
|
|
105
|
+
成功是 `inputs-verified` 且 `ready_for_agent: false`。这允许准备前端工程设计、实现计划和合同,正式编码仍须批准且当前的 Slice Contract。Handoff v5 必须明确 `prototype`、`existing-ui-baseline` 或有原因的 `not-applicable`;发现业务、API 或 UI 基线缺口时回交维护方,不在前端仓悄悄重定义。
|
|
103
106
|
|
|
104
107
|
## 6. 实现、联调与业务验收
|
|
105
108
|
|
|
@@ -2,13 +2,29 @@
|
|
|
2
2
|
import { parseArgs } from 'node:util';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { exportBackendDelivery, openBackendDelivery, importBackendDelivery } from './lib/backend-delivery.mjs';
|
|
5
|
+
import { read, safe, ensure } from './lib/strategic-handoff-io.mjs';
|
|
6
|
+
|
|
7
|
+
async function preflightExport(values) {
|
|
8
|
+
const root=path.resolve(values['source-root']),delivery=read(safe(root,values.delivery));
|
|
9
|
+
const document=read(safe(root,delivery.slice_contract.ref)),contract=document.slice_contract||document;
|
|
10
|
+
const identity=contract.resolution?.architecture_identity||contract.backend?.architecture_identity||contract.architecture_identity;
|
|
11
|
+
ensure(identity?.schema_version!==2||values['preflight-input'],'preflight-required: 既有工程身份 v2 导出必须提供 --preflight-input <file>;先按 docs/process/delivery-preflight.md 准备源资产清单并执行 export 阶段只读预检');
|
|
12
|
+
if(!values['preflight-input'])return;
|
|
13
|
+
const {preflightDelivery}=await import('./lib/delivery-preflight.mjs');
|
|
14
|
+
const input=read(path.resolve(values['preflight-input']));
|
|
15
|
+
ensure(!input.delivery_kind||input.delivery_kind==='backend-delivery','preflight-scope-conflict: 后端导出只能使用 backend-delivery 清单');
|
|
16
|
+
ensure(path.resolve(root,input.governance_root||'.')===root,'preflight-scope-conflict: 预检治理根与导出来源不同');
|
|
17
|
+
ensure(input.assets?.backend_delivery?.ref===values.delivery,'preflight-scope-conflict: 预检未绑定本次导出的 delivery 源文件');
|
|
18
|
+
const result=await preflightDelivery({...input,delivery_kind:'backend-delivery'},{stage:'export',root});
|
|
19
|
+
if(result.exit_code!==0){const error=new TypeError('delivery-preflight-blocked: 请按每项 recovery 补证,再从正常导出入口重试');error.preflight=result;throw error;}
|
|
20
|
+
}
|
|
5
21
|
try {
|
|
6
|
-
const {values,positionals}=parseArgs({allowPositionals:true,options:{'source-root':{type:'string'},delivery:{type:'string'},output:{type:'string'},zip:{type:'boolean'},bundle:{type:'string'},'target-root':{type:'string'}}});
|
|
22
|
+
const {values,positionals}=parseArgs({allowPositionals:true,options:{'source-root':{type:'string'},delivery:{type:'string'},output:{type:'string'},zip:{type:'boolean'},bundle:{type:'string'},'target-root':{type:'string'},'preflight-input':{type:'string'}}});
|
|
7
23
|
if(positionals.length!==1)throw new TypeError('必须指定 export / verify / import');
|
|
8
24
|
let result;
|
|
9
|
-
if(positionals[0]==='export'&&values['source-root']&&values.delivery&&values.output)result=await exportBackendDelivery({sourceRoot:values['source-root'],deliveryRef:values.delivery,output:values.output,zip:values.zip});
|
|
25
|
+
if(positionals[0]==='export'&&values['source-root']&&values.delivery&&values.output){await preflightExport(values);result=await exportBackendDelivery({sourceRoot:values['source-root'],deliveryRef:values.delivery,output:values.output,zip:values.zip});}
|
|
10
26
|
else if(positionals[0]==='verify'&&values.bundle)result=await openBackendDelivery(path.resolve(values.bundle),b=>({result:'verified',delivery_id:b.delivery.delivery_id,version:b.delivery.version,bundle_digest:b.manifest.bundle_digest,live_service_checked:false}));
|
|
11
27
|
else if(positionals[0]==='import'&&values.bundle&&values['target-root'])result=await importBackendDelivery({bundle:path.resolve(values.bundle),targetRoot:values['target-root']});
|
|
12
|
-
else throw new TypeError('用法: backend-delivery export --source-root <repo> --delivery <ref> --output <new-dir> [--zip] | verify --bundle <dir|zip> | import --bundle <dir|zip> --target-root <repo>');
|
|
28
|
+
else throw new TypeError('用法: backend-delivery export --source-root <repo> --delivery <ref> --output <new-dir> [--preflight-input <file>] [--zip] | verify --bundle <dir|zip> | import --bundle <dir|zip> --target-root <repo>');
|
|
13
29
|
process.stdout.write(`${JSON.stringify(result,null,2)}\n`);
|
|
14
|
-
} catch(error) { process.stderr.write(`${JSON.stringify({result:'blocked',error:error.message})}\n`);process.exitCode=1; }
|
|
30
|
+
} catch(error) { process.stderr.write(`${JSON.stringify({result:'blocked',error:error.message,...(error.preflight?{preflight:error.preflight}:{})})}\n`);process.exitCode=1; }
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { ROOT, read, parse, safe, hash, digest, schema } from './strategic-handoff-io.mjs';
|
|
4
|
+
import { countersignRuleForGate } from './digital-human-roles.mjs';
|
|
5
|
+
import { validateApprovalRecord } from './approval-record.mjs';
|
|
6
|
+
import { assertImplementationDecision } from './user-decision.mjs';
|
|
7
|
+
import { loadSkillRegistry } from './skill-registry.mjs';
|
|
8
|
+
|
|
9
|
+
const contexts=new WeakMap();
|
|
10
|
+
const gateId='gate.slice-contract-approved';
|
|
11
|
+
const check=(ok,code,message)=>{if(!ok){const error=new TypeError(`${code}: ${message}`);error.code=code;throw error;}};
|
|
12
|
+
const same=(a,b)=>digest(a)===digest(b);
|
|
13
|
+
const ioFor=root=>({root,read:ref=>readFileSync(safe(root,path.relative(root,ref).split(path.sep).join('/')))});
|
|
14
|
+
|
|
15
|
+
/** Existing registrations require persisted input sections; array properties disappear in JSON. */
|
|
16
|
+
export function assertExistingSliceStructure(contract) {
|
|
17
|
+
const identity=contract?.resolution?.architecture_identity;
|
|
18
|
+
if(identity?.schema_version!==2||identity.source_kind!=='existing-registration')return;
|
|
19
|
+
const object=value=>value!==null&&typeof value==='object'&&!Array.isArray(value);
|
|
20
|
+
check(object(contract.lifecycle_refs),'EXECUTION_CONTRACT_INVALID','既有工程 Slice lifecycle_refs 必须是对象');
|
|
21
|
+
for(const field of ['ticket','engineering_baseline'])check(typeof contract.lifecycle_refs[field]==='string'&&contract.lifecycle_refs[field].trim(),'EXECUTION_CONTRACT_INVALID',`既有工程 Slice 缺少 lifecycle_refs.${field}`);
|
|
22
|
+
check(object(contract.readiness),'EXECUTION_CONTRACT_INVALID','既有工程 Slice readiness 必须是对象');
|
|
23
|
+
for(const field of ['blockers','stale_inputs','not_applicable'])check(Array.isArray(contract.readiness[field]),'EXECUTION_CONTRACT_INVALID',`既有工程 Slice readiness.${field} 必须是数组`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Reads original local approval; a contract's own approved status never establishes permission. */
|
|
27
|
+
export function verifySliceContractApproval(binding,{root=process.cwd(),contract:expected}={}) {
|
|
28
|
+
root=path.resolve(root);
|
|
29
|
+
check(binding?.ref&&binding?.digest&&binding?.approval_ref,'EXECUTION_APPROVAL_REQUIRED','需要当前持久化 Slice 的 ref/digest/approval_ref');
|
|
30
|
+
const bytes=readFileSync(safe(root,binding.ref));
|
|
31
|
+
check(hash(bytes)===binding.digest,'EXECUTION_CONTRACT_STALE','Slice 原始字节与绑定不一致');
|
|
32
|
+
const document=parse(bytes),contract=document.slice_contract||document;
|
|
33
|
+
check(contract.schema_version===2&&contract.status==='approved'&&typeof contract.contract_id==='string'&&contract.contract_id&&typeof contract.contract_version==='string'&&contract.contract_version&&typeof contract.slice_id==='string'&&contract.slice_id,'EXECUTION_CONTRACT_INVALID','需要已批准且有身份的持久化 Slice v2');
|
|
34
|
+
assertExistingSliceStructure(contract);
|
|
35
|
+
check((!binding.id||binding.id===contract.contract_id)&&(!binding.version||binding.version===contract.contract_version),'EXECUTION_CONTRACT_CONFLICT','当前合同身份或版本不匹配');
|
|
36
|
+
if(expected)check(same(expected.slice_contract||expected,contract),'EXECUTION_CONTRACT_CONFLICT','调用方合同与持久化原字节不一致');
|
|
37
|
+
const roles=read(safe(root,'docs/agents/digital-human-roles.yaml'));
|
|
38
|
+
const approval=read(safe(root,binding.approval_ref));
|
|
39
|
+
if(!countersignRuleForGate(roles.gate_policy,gateId)&&roles.gate_policy.orchestrator?.includes(gateId)) {
|
|
40
|
+
// The current lifecycle already owns this gate. Consume its checkpoint and existing
|
|
41
|
+
// implementation-scope decision instead of inventing an approval-record countersignature.
|
|
42
|
+
check(approval?.gates&&approval?.human_review&&!approval.gate_id,'EXECUTION_APPROVAL_PROTOCOL','当前主控 gate 需要生命周期 checkpoint,不接受伪造 approval-record');
|
|
43
|
+
schema(approval,'docs/process/schemas/lifecycle-checkpoint.schema.json');
|
|
44
|
+
const gate=approval.gates?.[gateId],review=approval.human_review||{};
|
|
45
|
+
check(approval.repository_mode==='project-instance'&&approval.status!=='blocked'&&approval.blockers.length===0,'EXECUTION_APPROVAL_BLOCKED','主控 checkpoint 仍有阻断或不是产品实例');
|
|
46
|
+
check(gate?.status==='approved'&&gate.subject_ref===binding.ref,'EXECUTION_APPROVAL_SCOPE','主控 gate 未批准当前持久化 Slice');
|
|
47
|
+
check(review.implementation?.slice_contract_ref===binding.ref,'EXECUTION_APPROVAL_SCOPE','实施批准不指向当前 Slice 原始文件');
|
|
48
|
+
assertImplementationDecision({...review.implementation,user_decisions:review.user_decisions||[]},{...ioFor(root),rolesDoc:roles});
|
|
49
|
+
} else {
|
|
50
|
+
// Historical source profiles that declared this a countersign gate retain their policy.
|
|
51
|
+
validateApprovalRecord(approval,{...ioFor(root),rolesDoc:roles,requireApproved:true});
|
|
52
|
+
check(approval.gate_id===gateId&&approval.artifact_bindings?.some(item=>item.id===contract.contract_id&&item.version===contract.contract_version&&item.digest===binding.digest),'EXECUTION_APPROVAL_SCOPE','源会签未绑定当前 Slice 的身份、版本和字节');
|
|
53
|
+
}
|
|
54
|
+
return {contract,binding:structuredClone(binding),root};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function executionBasis(verified,{allowCompilerDrift=false}={}) {
|
|
58
|
+
const {contract}=verified,resolution=contract.resolution||{};
|
|
59
|
+
const compiler=read(safe(ROOT,'.agents/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml'));
|
|
60
|
+
if(!allowCompilerDrift)for(const [section,fields] of Object.entries(compiler.slice_contract_required))for(const field of fields)check(Object.hasOwn(section==='root'?contract:contract[section]||{},field),'EXECUTION_CONTRACT_INVALID',`合同缺少 ${section}.${field}`);
|
|
61
|
+
check(Array.isArray(contract.common?.allowed_write_paths)&&contract.common.allowed_write_paths.length>0&&contract.common.allowed_write_paths.every(value=>typeof value==='string'&&value.trim()),'EXECUTION_SCOPE_MISSING','合同缺少已批准写范围');
|
|
62
|
+
check(Array.isArray(contract.readiness?.blockers)&&!contract.readiness.blockers.length&&Array.isArray(contract.readiness?.stale_inputs)&&!contract.readiness.stale_inputs.length,'EXECUTION_CONTRACT_STALE','合同就绪条件仍有阻断或过期输入');
|
|
63
|
+
if(!allowCompilerDrift)check(resolution.registry_digest===digest(loadSkillRegistry()).slice(7)&&resolution.compiler_contract_digest===digest(compiler).slice(7),'EXECUTION_CONTRACT_STALE','编译依据已改变,应重新编译批准');
|
|
64
|
+
check(resolution.freshness==='current','EXECUTION_CONTRACT_STALE','resolution 不是 current');
|
|
65
|
+
if(resolution.architecture_identity)check(resolution.architecture_identity_digest===digest(resolution.architecture_identity).slice(7),'EXECUTION_CONTRACT_STALE','编译架构身份摘要不一致');
|
|
66
|
+
return verified;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function createApprovedExecutionContext(binding,options={}) {
|
|
70
|
+
const verified=executionBasis(verifySliceContractApproval(binding,options));
|
|
71
|
+
const context=Object.freeze({kind:'approved-slice-execution-context'});
|
|
72
|
+
contexts.set(context,{binding:verified.binding,root:verified.root,allowCompilerDrift:false});
|
|
73
|
+
return context;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** A prior approved scope may authenticate bounded output while current compiler facts are recomputed. */
|
|
77
|
+
export function createApprovedRecompilationContext(binding,options={}) {
|
|
78
|
+
const verified=executionBasis(verifySliceContractApproval(binding,options),{allowCompilerDrift:true});
|
|
79
|
+
const context=Object.freeze({kind:'approved-slice-recompilation-context'});
|
|
80
|
+
contexts.set(context,{binding:verified.binding,root:verified.root,allowCompilerDrift:true});
|
|
81
|
+
return context;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Revalidate original bytes on every boundary; a serialized/caller-invented context is rejected. */
|
|
85
|
+
export function assertApprovedExecutionContext(context,{root=process.cwd(),contract,architectureIdentity,architectureEvidence,technicalDesign,sliceId}={}) {
|
|
86
|
+
const saved=contexts.get(context);
|
|
87
|
+
check(saved&&saved.root===path.resolve(root),'EXECUTION_CONTEXT_UNTRUSTED','只允许从当前原始 Slice 与本地批准生成的执行上下文');
|
|
88
|
+
const verified=executionBasis(verifySliceContractApproval(saved.binding,{root,contract}),{allowCompilerDrift:saved.allowCompilerDrift});
|
|
89
|
+
const current=verified.contract,resolution=current.resolution;
|
|
90
|
+
if(sliceId)check(current.slice_id===sliceId,'EXECUTION_SCOPE_CONFLICT','执行上下文属于另一切片');
|
|
91
|
+
if(architectureIdentity)check(same(resolution.architecture_identity,architectureIdentity),'EXECUTION_INPUT_REPLACED','执行上下文不允许替换架构身份或固定源码输入');
|
|
92
|
+
if(architectureEvidence)check(same(resolution.architecture_evidence,architectureEvidence),'EXECUTION_INPUT_REPLACED','执行上下文不允许替换原始架构证据');
|
|
93
|
+
if(technicalDesign) {
|
|
94
|
+
const binding=resolution.technical_design;
|
|
95
|
+
check(binding?.ref&&binding.digest,'EXECUTION_DESIGN_MISSING','Slice 未绑定当前技术设计');
|
|
96
|
+
const bytes=readFileSync(safe(root,binding.ref));
|
|
97
|
+
check(hash(bytes)===binding.digest&&same(parse(bytes),technicalDesign),'EXECUTION_INPUT_REPLACED','执行上下文不允许替换技术设计');
|
|
98
|
+
}
|
|
99
|
+
return {allowed_write_paths:[...current.common.allowed_write_paths],contract:current};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function approvedExecutionBinding(context) {
|
|
103
|
+
const saved=contexts.get(context);
|
|
104
|
+
check(saved,'EXECUTION_CONTEXT_UNTRUSTED','不能序列化未验证的执行上下文');
|
|
105
|
+
return structuredClone(saved.binding);
|
|
106
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { loadSkillRegistry } from "./skill-registry.mjs";
|
|
3
|
+
import { validateExistingArchitecture, verifyExistingArchitecture } from "./existing-backend-architecture.mjs";
|
|
3
4
|
|
|
4
5
|
export function architectureDigest(value) {
|
|
5
6
|
const stable = (item) => Array.isArray(item) ? item.map(stable) : item && typeof item === "object"
|
|
@@ -9,6 +10,8 @@ export function architectureDigest(value) {
|
|
|
9
10
|
|
|
10
11
|
export function validateArchitectureIdentity(identity, registry = loadSkillRegistry()) {
|
|
11
12
|
if (!identity || typeof identity !== "object") throw new TypeError("缺少 architecture_identity;请从工程基线重新编译");
|
|
13
|
+
if (identity.schema_version === 2) return validateExistingArchitecture(identity, registry);
|
|
14
|
+
if (identity.schema_version !== undefined || identity.source_kind !== undefined) throw new TypeError("不支持的 architecture_identity 来源或版本");
|
|
12
15
|
const profile = registry.architecture_profiles?.[identity.architecture_profile];
|
|
13
16
|
if (!profile || identity.architecture_family !== profile.architecture_family || identity.generator_skill !== profile.generator_skill) {
|
|
14
17
|
throw new TypeError("architecture_identity 的架构族、Profile 或生成器不匹配");
|
|
@@ -28,6 +31,15 @@ export function validateArchitectureIdentity(identity, registry = loadSkillRegis
|
|
|
28
31
|
return profile;
|
|
29
32
|
}
|
|
30
33
|
|
|
34
|
+
// Existing projects must present original on-disk evidence, not three copies supplied by a caller.
|
|
35
|
+
export function verifyArchitectureEvidence(identity, evidence, { root, registry = loadSkillRegistry(), execution } = {}) {
|
|
36
|
+
validateArchitectureIdentity(identity, registry);
|
|
37
|
+
if (identity.schema_version === 2) return verifyExistingArchitecture(identity, evidence, { root, registry, execution });
|
|
38
|
+
if (!evidence?.engineering_baseline || !evidence?.repository_registration || !evidence?.manifest) throw new TypeError("缺少工程基线、仓库登记或 Manifest 架构证据");
|
|
39
|
+
assertArchitectureAgreement(identity, evidence, registry);
|
|
40
|
+
return { source_kind: "scaffold", bindings: evidence };
|
|
41
|
+
}
|
|
42
|
+
|
|
31
43
|
export function assertArchitectureAgreement(identity, evidence, registry) {
|
|
32
44
|
validateArchitectureIdentity(identity, registry);
|
|
33
45
|
for (const [name, source] of Object.entries(evidence ?? {})) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { verifySliceContractApproval } from './approved-execution-context.mjs';
|
|
1
2
|
import { cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync } from 'node:fs';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { tmpdir } from 'node:os';
|
|
@@ -17,6 +18,7 @@ function boundFile(root, binding) {
|
|
|
17
18
|
|
|
18
19
|
async function approvedFile(root, binding, gate) {
|
|
19
20
|
const bytes=boundFile(root,binding);
|
|
21
|
+
if(gate==='gate.slice-contract-approved'){verifySliceContractApproval(binding,{root});return bytes;}
|
|
20
22
|
const record=read(safe(root,binding.approval_ref));
|
|
21
23
|
const roles=sourceApprovalPolicy(read(safe(root,'docs/agents/digital-human-roles.yaml')));
|
|
22
24
|
await sourceApproval(record,roles,root);
|
|
@@ -38,7 +40,7 @@ function verification(root, binding, basis, kind) {
|
|
|
38
40
|
return record;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
export async function inspectBackendDelivery(root, ref) {
|
|
43
|
+
export async function inspectBackendDelivery(root, ref, { readOnly = false } = {}) {
|
|
42
44
|
project(root);
|
|
43
45
|
const delivery=read(safe(root,ref));
|
|
44
46
|
schema(delivery,'docs/process/schemas/backend-delivery.schema.json');
|
|
@@ -57,7 +59,7 @@ export async function inspectBackendDelivery(root, ref) {
|
|
|
57
59
|
verification(root,delivery.verification.deployment,basis,'backend-deployment');
|
|
58
60
|
return openBundle(safe(root,delivery.strategic_bundle_ref),bundle=>{
|
|
59
61
|
ensure(bundle.manifest.bundle_digest===delivery.strategic_bundle_digest,'后端交付与战略版本不一致');
|
|
60
|
-
if(bundle.handoff.schema_version
|
|
62
|
+
if([4,5].includes(bundle.handoff.schema_version)){
|
|
61
63
|
const route=bundle.handoff.consumer_routes.find(item=>item.capability==='backend-technical-design');
|
|
62
64
|
ensure(route&&route.activation!=='not-applicable'&&delivery.strategic_route_id===route.route_id,'后端交付未绑定当前 backend-technical-design route_id');
|
|
63
65
|
}
|
|
@@ -71,7 +73,7 @@ export async function inspectBackendDelivery(root, ref) {
|
|
|
71
73
|
}
|
|
72
74
|
ensure(delivery.scope.operation_ids.every(id=>tests.operation_ids.includes(id)),'后端契约验证未覆盖交付接口');
|
|
73
75
|
return {delivery,basis};
|
|
74
|
-
});
|
|
76
|
+
}, { readOnly });
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
function validManifest(manifest,root) {
|
|
@@ -168,9 +170,11 @@ export async function importBackendDelivery({bundle,targetRoot}) {
|
|
|
168
170
|
write(staging,'import-receipt.json',json(receipt));
|
|
169
171
|
const strategicHandoff={import_receipt_ref:strategic.receipt_ref,bundle_digest:strategicReceipt.bundle_digest,...(trace.route_id?{route_id:trace.route_id}:{}),context_reconciliation_ref:'',rows:trace.rows.map(({tactical_refs,test_seam_refs,...row})=>({...row,frontend_case_refs:[]}))};
|
|
170
172
|
if(strategicReceipt.schema_version===2){
|
|
171
|
-
ensure(frontendRoute,'
|
|
172
|
-
const preflightRef=frontendRoute.artifact_refs.find(item=>item.endsWith('frontend-strategic-preflight-draft.json'));ensure(preflightRef,'
|
|
173
|
-
|
|
173
|
+
ensure(frontendRoute,'Import Receipt 未选择 frontend-engineering-design 能力');
|
|
174
|
+
const preflightRef=frontendRoute.artifact_refs.find(item=>item.endsWith('frontend-strategic-preflight-draft.json'));ensure(preflightRef,'缺少 Frontend Strategic Preflight 草案');
|
|
175
|
+
const preflight=read(safe(target,preflightRef));
|
|
176
|
+
ensure([1,2].includes(preflight.schema_version),'未知 Frontend Strategic Preflight 版本');
|
|
177
|
+
write(staging,'frontend-acceptance-draft.json',json({schema_version:preflight.schema_version===2?3:2,...(preflight.schema_version===2?{ui_baseline_kind:preflight.ui_baseline_kind}:{}),status:'draft',slice_id:b.delivery.scope.slice_id,strategic_preflight:{ref:preflightRef,digest:hash(readFileSync(safe(target,preflightRef)))},backend_dependency:{mode:'required',route_id:b.delivery.strategic_route_id},backend_delivery:{import_receipt_ref:`${ref}/import-receipt.json`,bundle_digest:b.manifest.bundle_digest},strategic_handoff:strategicHandoff,frontend_cases:[]}));
|
|
174
178
|
}else write(staging,'frontend-acceptance-draft.json',json({schema_version:1,status:'draft',slice_id:b.delivery.scope.slice_id,backend_delivery:{import_receipt_ref:`${ref}/import-receipt.json`,bundle_digest:b.manifest.bundle_digest},strategic_handoff:strategicHandoff,frontend_cases:[]}));
|
|
175
179
|
ensure(!existsSync(destination),'后端包导入并发冲突');renameSync(staging,destination);
|
|
176
180
|
return {result:'imported-pending-acceptance',receipt_ref:`${ref}/import-receipt.json`,acceptance_ref:`${ref}/frontend-acceptance-draft.json`};
|