@pm_zhousl/xinyun-ai-init 2.0.0 → 3.0.0

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.
Files changed (199) hide show
  1. package/README.md +29 -39
  2. package/bin/xinyun-ai-init.js +121 -175
  3. package/init/xinyun-ai-init/README.md +26 -144
  4. package/init/xinyun-ai-init/rules/v3-skill-runtime.md +45 -0
  5. package/init/xinyun-ai-init/runtime/migrate-v3.js +115 -0
  6. package/init/xinyun-ai-init/runtime/route-skill.js +69 -0
  7. package/init/xinyun-ai-init/runtime-manifest.json +26 -0
  8. package/init/xinyun-ai-init/skills/registry.json +112 -0
  9. package/init/xinyun-ai-init/templates/AGENTS.template.md +4 -27
  10. package/init/xinyun-ai-init/templates/README.template.md +3 -31
  11. package/init/xinyun-ai-init/templates/control-plane-index.template.json +5 -24
  12. package/init/xinyun-ai-init/templates/core-rules.template.md +9 -57
  13. package/init/xinyun-ai-init/templates/current-task.template.md +3 -19
  14. package/init/xinyun-ai-init/templates/manifest.template.json +13 -67
  15. package/init/xinyun-ai-init/templates/project-context.template.json +3 -11
  16. package/init/xinyun-ai-init/templates/project-index.template.json +5 -51
  17. package/init/xinyun-ai-init/templates/skill-run-record.template.json +4 -16
  18. package/init/xinyun-ai-init/templates/skill-runtime-route.template.json +3 -24
  19. package/init/xinyun-ai-init/templates/skills-assignments.template.json +3 -21
  20. package/init/xinyun-ai-init/templates/skills-registry.template.json +5 -29
  21. package/init/xinyun-ai-init/templates/task-graph.template.json +3 -5
  22. package/init/xinyun-ai-init/templates/task-index.template.json +3 -31
  23. package/init/xinyun-ai-init/version.json +8 -8
  24. package/package.json +8 -14
  25. package/scripts/run-v3-runtime-probe.js +8 -0
  26. package/scripts/verify-legacy-cleanup.js +24 -0
  27. package/scripts/verify-release-gate.js +10 -23
  28. package/scripts/verify-rules-tarball-security.js +1 -1
  29. package/scripts/verify-skill-runtime.js +33 -0
  30. package/scripts/verify-tarball.js +42 -0
  31. package/scripts/verify-v3-package.js +70 -0
  32. package/test-scenarios/v3.0.0-behavior-evidence.json +25 -0
  33. package/test-scenarios/v3.0.0-scenarios.md +41 -0
  34. package/init/xinyun-ai-init/prompt.md +0 -1
  35. package/init/xinyun-ai-init/rules/coordination.md +0 -43
  36. package/init/xinyun-ai-init/rules/directory-self-completion.md +0 -100
  37. package/init/xinyun-ai-init/rules/frameworks/README.md +0 -56
  38. package/init/xinyun-ai-init/rules/frameworks/backend/php/thinkphp.md +0 -42
  39. package/init/xinyun-ai-init/rules/frameworks/frontend/uni-app.md +0 -36
  40. package/init/xinyun-ai-init/rules/frameworks/frontend/wechat-miniprogram.md +0 -36
  41. package/init/xinyun-ai-init/rules/frontend-audit.md +0 -9
  42. package/init/xinyun-ai-init/rules/init-rules.md +0 -145
  43. package/init/xinyun-ai-init/rules/self-learning-rules.md +0 -16
  44. package/init/xinyun-ai-init/rules/session-workbench.md +0 -333
  45. package/init/xinyun-ai-init/rules/skills.md +0 -23
  46. package/init/xinyun-ai-init/rules/temporary-sessions.md +0 -13
  47. package/init/xinyun-ai-init/rules/upgrade-rules.md +0 -161
  48. package/init/xinyun-ai-init/rules/v1.10.2-contract.md +0 -30
  49. package/init/xinyun-ai-init/rules/v1.11.0-acceleration.md +0 -27
  50. package/init/xinyun-ai-init/rules/v1.12.0-recovery.md +0 -34
  51. package/init/xinyun-ai-init/rules/v1.12.1-provider-session-binding.md +0 -25
  52. package/init/xinyun-ai-init/rules/v1.13.0-host-adapter.md +0 -43
  53. package/init/xinyun-ai-init/rules/v1.14.0-agent-core.md +0 -35
  54. package/init/xinyun-ai-init/rules/v1.15.0-session-binding.md +0 -44
  55. package/init/xinyun-ai-init/rules/v1.16.0-capability-efficiency.md +0 -23
  56. package/init/xinyun-ai-init/rules/v2.0.0-shared-project-conversations.md +0 -68
  57. package/init/xinyun-ai-init/rules/v2.0.0-single-session-skills.md +0 -89
  58. package/init/xinyun-ai-init/scripts/README.md +0 -16
  59. package/init/xinyun-ai-init/templates/agent-capabilities.template.json +0 -27
  60. package/init/xinyun-ai-init/templates/agent-profile.template.json +0 -21
  61. package/init/xinyun-ai-init/templates/archive-transaction.template.json +0 -15
  62. package/init/xinyun-ai-init/templates/bootstrap-snapshot.template.json +0 -22
  63. package/init/xinyun-ai-init/templates/capabilities.template.json +0 -19
  64. package/init/xinyun-ai-init/templates/codegraph-incremental-record.template.json +0 -21
  65. package/init/xinyun-ai-init/templates/conversation-binding.template.json +0 -26
  66. package/init/xinyun-ai-init/templates/conversation-event.template.json +0 -24
  67. package/init/xinyun-ai-init/templates/conversation-registry.template.json +0 -15
  68. package/init/xinyun-ai-init/templates/conversation-stream-head.template.json +0 -14
  69. package/init/xinyun-ai-init/templates/conversation-sync-cursor.template.json +0 -13
  70. package/init/xinyun-ai-init/templates/coordination-change-ledger.template.json +0 -15
  71. package/init/xinyun-ai-init/templates/coordination-conflict-record.template.json +0 -18
  72. package/init/xinyun-ai-init/templates/coordination-contract-snapshot.template.json +0 -9
  73. package/init/xinyun-ai-init/templates/coordination-project-facts.template.json +0 -20
  74. package/init/xinyun-ai-init/templates/coordination-transaction.template.json +0 -16
  75. package/init/xinyun-ai-init/templates/database-authorization.template.json +0 -53
  76. package/init/xinyun-ai-init/templates/final-delivery.template.json +0 -22
  77. package/init/xinyun-ai-init/templates/fixed-materialization.template.json +0 -12
  78. package/init/xinyun-ai-init/templates/framework-profile.template.json +0 -48
  79. package/init/xinyun-ai-init/templates/framework-profile.template.md +0 -39
  80. package/init/xinyun-ai-init/templates/frontend-audit.template.json +0 -27
  81. package/init/xinyun-ai-init/templates/handoff.template.json +0 -27
  82. package/init/xinyun-ai-init/templates/host-capabilities.template.json +0 -37
  83. package/init/xinyun-ai-init/templates/host-preflight.template.json +0 -33
  84. package/init/xinyun-ai-init/templates/html-migration-asset-map.template.md +0 -6
  85. package/init/xinyun-ai-init/templates/html-migration-compatibility-matrix.template.md +0 -6
  86. package/init/xinyun-ai-init/templates/html-migration-open-issues.template.md +0 -12
  87. package/init/xinyun-ai-init/templates/html-migration-pilot-plan.template.md +0 -21
  88. package/init/xinyun-ai-init/templates/html-migration-record.template.json +0 -36
  89. package/init/xinyun-ai-init/templates/html-migration-route-map.template.md +0 -6
  90. package/init/xinyun-ai-init/templates/html-migration-scope.template.md +0 -28
  91. package/init/xinyun-ai-init/templates/init-result.template.json +0 -25
  92. package/init/xinyun-ai-init/templates/initialization-cache.template.json +0 -13
  93. package/init/xinyun-ai-init/templates/initialization-change-report.template.json +0 -14
  94. package/init/xinyun-ai-init/templates/initialization-recovery.template.json +0 -24
  95. package/init/xinyun-ai-init/templates/initialization-stages.template.json +0 -18
  96. package/init/xinyun-ai-init/templates/initialization-timing.template.json +0 -16
  97. package/init/xinyun-ai-init/templates/local-query-index.template.json +0 -15
  98. package/init/xinyun-ai-init/templates/managed-baseline.template.json +0 -17
  99. package/init/xinyun-ai-init/templates/manual-session-binding.template.json +0 -45
  100. package/init/xinyun-ai-init/templates/manual-session-recovery.template.json +0 -53
  101. package/init/xinyun-ai-init/templates/multi-conversation-migration.template.json +0 -24
  102. package/init/xinyun-ai-init/templates/onboarding-report.template.json +0 -30
  103. package/init/xinyun-ai-init/templates/orchestrator.template.json +0 -28
  104. package/init/xinyun-ai-init/templates/parallelism.template.json +0 -13
  105. package/init/xinyun-ai-init/templates/performance-metrics.template.json +0 -17
  106. package/init/xinyun-ai-init/templates/preflight-report.template.json +0 -25
  107. package/init/xinyun-ai-init/templates/project-check.template.md +0 -56
  108. package/init/xinyun-ai-init/templates/project-guide.template.md +0 -57
  109. package/init/xinyun-ai-init/templates/project-identity.template.json +0 -23
  110. package/init/xinyun-ai-init/templates/project-status.template.json +0 -28
  111. package/init/xinyun-ai-init/templates/provider-adapter.template.json +0 -25
  112. package/init/xinyun-ai-init/templates/provider-session-binding.template.json +0 -77
  113. package/init/xinyun-ai-init/templates/re-takeover-record.template.json +0 -37
  114. package/init/xinyun-ai-init/templates/requirement-packet.template.json +0 -23
  115. package/init/xinyun-ai-init/templates/role-execution.template.md +0 -72
  116. package/init/xinyun-ai-init/templates/role-session-binding.template.json +0 -105
  117. package/init/xinyun-ai-init/templates/role-subtask.template.md +0 -36
  118. package/init/xinyun-ai-init/templates/session-binding.template.json +0 -38
  119. package/init/xinyun-ai-init/templates/session-candidates.template.json +0 -19
  120. package/init/xinyun-ai-init/templates/shared-project-snapshot.template.json +0 -24
  121. package/init/xinyun-ai-init/templates/single-session-migration.template.json +0 -31
  122. package/init/xinyun-ai-init/templates/sync-check.template.json +0 -23
  123. package/init/xinyun-ai-init/templates/takeover-baseline.template.json +0 -17
  124. package/init/xinyun-ai-init/templates/takeover-gate.template.json +0 -22
  125. package/init/xinyun-ai-init/templates/task-history.template.md +0 -35
  126. package/init/xinyun-ai-init/templates/task-lease.template.json +0 -19
  127. package/init/xinyun-ai-init/templates/task-lock.template.json +0 -31
  128. package/init/xinyun-ai-init/templates/task-main.template.md +0 -38
  129. package/init/xinyun-ai-init/templates/task-result.template.json +0 -23
  130. package/init/xinyun-ai-init/templates/team/README.md +0 -51
  131. package/init/xinyun-ai-init/templates/team/assignments.json +0 -49
  132. package/init/xinyun-ai-init/templates/team/confirmations/chief-engineer.md +0 -24
  133. package/init/xinyun-ai-init/templates/team/confirmations/programmer.md +0 -24
  134. package/init/xinyun-ai-init/templates/team/confirmations/project-owner.md +0 -24
  135. package/init/xinyun-ai-init/templates/team/confirmations/project-product.md +0 -24
  136. package/init/xinyun-ai-init/templates/team/confirmations/test-reviewer.md +0 -24
  137. package/init/xinyun-ai-init/templates/team/file-ownership.json +0 -32
  138. package/init/xinyun-ai-init/templates/team/members.json +0 -61
  139. package/init/xinyun-ai-init/templates/team/responsibility-matrix.json +0 -81
  140. package/init/xinyun-ai-init/templates/team/roles.json +0 -71
  141. package/init/xinyun-ai-init/templates/team/understandings/chief-engineer.md +0 -23
  142. package/init/xinyun-ai-init/templates/team/understandings/programmer.md +0 -23
  143. package/init/xinyun-ai-init/templates/team/understandings/project-owner.md +0 -23
  144. package/init/xinyun-ai-init/templates/team/understandings/project-product.md +0 -23
  145. package/init/xinyun-ai-init/templates/team/understandings/test-reviewer.md +0 -23
  146. package/init/xinyun-ai-init/templates/technical-impact-packet.template.json +0 -31
  147. package/init/xinyun-ai-init/templates/technical-landscape.template.json +0 -41
  148. package/init/xinyun-ai-init/templates/temporary-session.template.json +0 -32
  149. package/init/xinyun-ai-init/templates/workstreams-readme.template.md +0 -36
  150. package/scripts/collect-v1.10-evidence.js +0 -159
  151. package/scripts/collect-v1.14-local-evidence.js +0 -66
  152. package/scripts/collect-v1.15-real-evidence.js +0 -114
  153. package/scripts/collect-v1.16-evidence.js +0 -48
  154. package/scripts/collect-v2-evidence.js +0 -35
  155. package/scripts/run-v1.16-runtime-probe.js +0 -91
  156. package/scripts/run-v2-runtime-probe.js +0 -110
  157. package/scripts/verify-init-package.js +0 -2297
  158. package/scripts/verify-multi-conversation-contract.js +0 -61
  159. package/scripts/verify-re-takeover-contract.js +0 -54
  160. package/scripts/verify-rules-package.js +0 -1287
  161. package/scripts/verify-v2-package.js +0 -210
  162. package/scripts/verify-v2-tarball.js +0 -73
  163. package/test-scenarios/README.md +0 -130
  164. package/test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/README.md +0 -23
  165. package/test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/after/project-status.json +0 -7
  166. package/test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/before/project-status.json +0 -7
  167. package/test-scenarios/fixtures/v1.9.0-behavior-fixture/README.md +0 -9
  168. package/test-scenarios/multi-conversation-evidence.json +0 -26
  169. package/test-scenarios/multi-conversation-scenarios.md +0 -16
  170. package/test-scenarios/re-takeover-evidence.json +0 -20
  171. package/test-scenarios/re-takeover-scenarios.md +0 -33
  172. package/test-scenarios/review-template.md +0 -165
  173. package/test-scenarios/scenarios.md +0 -1273
  174. package/test-scenarios/v1.10.0-behavior-evidence.json +0 -31
  175. package/test-scenarios/v1.10.0-scenarios.md +0 -96
  176. package/test-scenarios/v1.10.2-scenarios.md +0 -38
  177. package/test-scenarios/v1.11.0-scenarios.md +0 -30
  178. package/test-scenarios/v1.12.0-behavior-evidence.json +0 -29
  179. package/test-scenarios/v1.12.0-scenarios.md +0 -51
  180. package/test-scenarios/v1.12.1-behavior-evidence.json +0 -27
  181. package/test-scenarios/v1.12.1-scenarios.md +0 -42
  182. package/test-scenarios/v1.13.0-behavior-evidence.json +0 -650
  183. package/test-scenarios/v1.13.0-scenarios.md +0 -94
  184. package/test-scenarios/v1.14.0-behavior-evidence.json +0 -780
  185. package/test-scenarios/v1.14.0-scenarios.md +0 -63
  186. package/test-scenarios/v1.15.0-behavior-evidence.json +0 -476
  187. package/test-scenarios/v1.15.0-scenarios.md +0 -57
  188. package/test-scenarios/v1.16.0-behavior-evidence.json +0 -46
  189. package/test-scenarios/v1.16.0-real-host-probe.json +0 -132
  190. package/test-scenarios/v1.16.0-scenarios.md +0 -19
  191. package/test-scenarios/v1.7.0-scenarios.md +0 -91
  192. package/test-scenarios/v1.7.1-scenarios.md +0 -130
  193. package/test-scenarios/v1.7.2-scenarios.md +0 -51
  194. package/test-scenarios/v1.7.3-scenarios.md +0 -79
  195. package/test-scenarios/v1.8.0-scenarios.md +0 -39
  196. package/test-scenarios/v1.9.0-behavior-evidence.json +0 -269
  197. package/test-scenarios/v1.9.0-scenarios.md +0 -55
  198. package/test-scenarios/v2.0.0-behavior-evidence.json +0 -40
  199. package/test-scenarios/v2.0.0-scenarios.md +0 -21
@@ -1,2297 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require("fs");
4
- const path = require("path");
5
- const crypto = require("crypto");
6
-
7
- const root = path.resolve(__dirname, "..");
8
- if (require(path.join(root, "package.json")).version.startsWith("2.")) {
9
- const targetScript = process.argv.includes("--tarball") ? "verify-v2-tarball.js" : "verify-v2-package.js";
10
- const result = require("child_process").spawnSync(process.execPath, [path.join(__dirname, targetScript), ...process.argv.slice(2)], { stdio: "inherit" });
11
- process.exit(typeof result.status === "number" ? result.status : 1);
12
- }
13
- const initRoot = path.join(root, "init", "xinyun-ai-init");
14
- const CURRENT_VERSION = "1.16.0";
15
-
16
- const checks = [];
17
-
18
- function rel(filePath) {
19
- return path.relative(root, filePath).replace(/\\/g, "/");
20
- }
21
-
22
- function readText(relativePath) {
23
- const filePath = path.join(root, relativePath);
24
- return fs.readFileSync(filePath, "utf8");
25
- }
26
-
27
- function addCheck(name, ok, detail) {
28
- checks.push({ name, ok, detail });
29
- }
30
-
31
- function requireFile(relativePath) {
32
- const filePath = path.join(root, relativePath);
33
- addCheck(`文件存在:${relativePath}`, fs.existsSync(filePath), "缺少必需文件");
34
- }
35
-
36
- function requireIncludes(relativePath, snippets) {
37
- const content = readText(relativePath);
38
- for (const snippet of snippets) {
39
- const expectedSnippet = snippet === "当前规则版本:`1.9.0`" ? `当前规则版本:\`${CURRENT_VERSION}\`` : snippet;
40
- addCheck(
41
- `${relativePath} 包含:${snippet}`,
42
- content.includes(expectedSnippet),
43
- `未找到关键文本:${snippet}`
44
- );
45
- }
46
- }
47
-
48
- function markdownFieldValue(content, fieldName) {
49
- const escaped = fieldName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
50
- const match = content.match(new RegExp(`^- ${escaped}:(.+)$`, "m"));
51
- return match ? match[1].trim() : "";
52
- }
53
-
54
- function isIso8601Utc(value) {
55
- return (
56
- /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value) &&
57
- !Number.isNaN(Date.parse(value))
58
- );
59
- }
60
-
61
- function requireJson(relativePath) {
62
- try {
63
- JSON.parse(readText(relativePath));
64
- addCheck(`JSON 可解析:${relativePath}`, true);
65
- } catch (error) {
66
- addCheck(`JSON 可解析:${relativePath}`, false, error.message);
67
- }
68
- }
69
-
70
- function requireMarkdownBalanced(relativePath) {
71
- const content = readText(relativePath);
72
- const fenceCount = (content.match(/```/g) || []).length;
73
- addCheck(
74
- `Markdown 代码块闭合:${relativePath}`,
75
- fenceCount % 2 === 0,
76
- `代码块围栏数量为 ${fenceCount}`
77
- );
78
- }
79
-
80
- function walkFiles(dirPath) {
81
- const result = [];
82
- for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
83
- const entryPath = path.join(dirPath, entry.name);
84
- if (entry.isDirectory()) {
85
- result.push(...walkFiles(entryPath));
86
- } else {
87
- result.push(entryPath);
88
- }
89
- }
90
- return result;
91
- }
92
-
93
- const v19SessionReuseFiles = [
94
- "init/xinyun-ai-init/README.md",
95
- "init/xinyun-ai-init/templates/AGENTS.template.md",
96
- "init/xinyun-ai-init/templates/core-rules.template.md",
97
- "init/xinyun-ai-init/templates/project-guide.template.md",
98
- "init/xinyun-ai-init/templates/project-check.template.md",
99
- "init/xinyun-ai-init/templates/role-execution.template.md",
100
- "init/xinyun-ai-init/rules/init-rules.md",
101
- "init/xinyun-ai-init/rules/upgrade-rules.md",
102
- "init/xinyun-ai-init/rules/session-workbench.md",
103
- ];
104
-
105
- const v19SessionKeyFields = [
106
- "projectRootHash",
107
- "workspaceScope",
108
- "repositoryScopeHash",
109
- "workstream",
110
- "taskId",
111
- "roleId",
112
- "provider",
113
- "targetVersion",
114
- ];
115
-
116
- function verifyV19SessionReuseText() {
117
- const legacyPatterns = [
118
- /\btaskId\s*\+\s*roleId\s*\+\s*provider\s*\+\s*targetVersion\b/,
119
- /JCS-SHA-256\s*\(\s*taskId\s*,\s*roleId\s*,\s*provider\s*,\s*targetVersion\s*\)/,
120
- /(?:roleSessionIdempotency|sessionIdempotencyKey|legacyCreationIndexFields)[^\n]{0,300}\{\s*taskId\s*,\s*roleId\s*,\s*provider\s*,\s*targetVersion\s*\}/,
121
- ];
122
- const allowedLegacyMarkers = [
123
- /legacy/i,
124
- /compatib/i,
125
- /兼容/,
126
- /不得参与候选选择/,
127
- /不参与候选选择/,
128
- /绝不参与/,
129
- /never used for candidate selection/i,
130
- /only.*creation/i,
131
- /只作/,
132
- /仅作/,
133
- ];
134
-
135
- for (const relativePath of v19SessionReuseFiles) {
136
- const content = readText(relativePath);
137
- const hits = [];
138
- for (const [index, line] of content.split(/\r?\n/).entries()) {
139
- if (!legacyPatterns.some((pattern) => pattern.test(line))) continue;
140
- const allowed = allowedLegacyMarkers.some((marker) => marker.test(line));
141
- hits.push({ line: index + 1, allowed, text: line.trim() });
142
- }
143
- const unauthorized = hits.filter((hit) => !hit.allowed);
144
- addCheck(
145
- `v1.9 会话复用文本扫描:${relativePath}`,
146
- unauthorized.length === 0,
147
- unauthorized.length === 0
148
- ? hits.length === 0
149
- ? "未发现旧四字段会话复用表述"
150
- : `仅发现兼容索引命中 ${hits.length} 处;均明确禁止候选选择、复用或跨项目判定`
151
- : `发现未标注兼容用途的旧四字段命中:${unauthorized.map((hit) => `L${hit.line}`).join(", ")}`
152
- );
153
- addCheck(
154
- `v1.9 完整会话复用键:${relativePath}`,
155
- v19SessionKeyFields.every((field) => content.includes(field)) && content.includes("RFC8785-JCS-SHA-256"),
156
- "正式可执行会话复用文本必须包含八字段和 RFC8785-JCS-SHA-256"
157
- );
158
- }
159
- }
160
-
161
- function verifyPackageFiles() {
162
- const packageJson = JSON.parse(readText("package.json"));
163
- const versionJson = JSON.parse(readText("init/xinyun-ai-init/version.json"));
164
- const manifestTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
165
- const expectedFiles = ["bin/", "init/", "scripts/", "test-scenarios/", "README.md"];
166
-
167
- for (const expected of expectedFiles) {
168
- addCheck(
169
- `package.json files 包含:${expected}`,
170
- Array.isArray(packageJson.files) && packageJson.files.includes(expected),
171
- "发布文件白名单缺少该路径"
172
- );
173
- }
174
-
175
- addCheck(
176
- "package.json scripts 包含 verify:init",
177
- packageJson.scripts && packageJson.scripts["verify:init"] === "node ./scripts/verify-init-package.js",
178
- "缺少发布前校验命令"
179
- );
180
- addCheck(
181
- "package.json scripts 包含 evidence:v1.10",
182
- packageJson.scripts && packageJson.scripts["evidence:v1.10"] === "node ./scripts/collect-v1.10-evidence.js",
183
- "缺少 v1.10 真实会话证据采集入口"
184
- );
185
-
186
- addCheck(
187
- "package.json 版本为当前版本",
188
- packageJson.version === CURRENT_VERSION,
189
- `当前版本为 ${packageJson.version}`
190
- );
191
- addCheck(
192
- "version.json 版本为当前版本",
193
- versionJson.version === CURRENT_VERSION,
194
- `当前版本为 ${versionJson.version}`
195
- );
196
- addCheck(
197
- "manifest.template.json 版本为当前版本",
198
- manifestTemplate.xinyunAiVersion === CURRENT_VERSION,
199
- `当前版本为 ${manifestTemplate.xinyunAiVersion}`
200
- );
201
- }
202
-
203
- function verifyCliBoundary() {
204
- const cli = readText("bin/xinyun-ai-init.js");
205
-
206
- requireIncludes("bin/xinyun-ai-init.js", [
207
- "This CLI only creates xinyun-ai-init/",
208
- "It does not create xinyun-ai/ or modify business code",
209
- "printNextStep",
210
- ]);
211
-
212
- addCheck(
213
- "CLI 目标目录仅为 xinyun-ai-init",
214
- cli.includes('const target = path.join(cwd, "xinyun-ai-init");'),
215
- "CLI 不应直接创建 xinyun-ai/"
216
- );
217
- }
218
-
219
- function verifyInitRules() {
220
- requireIncludes("init/xinyun-ai-init/README.md", [
221
- "用户发送一句话入口后,AI 可以按本 README 和 `templates/` 创建或补齐首次最小落盘清单。",
222
- "该授权只覆盖 AI 工作区初始化,不代表授权修改业务代码",
223
- "标准改动计划",
224
- "前端改动模式:样式微调 / 新页面 / 页面重写 / 组件重构 / 不涉及",
225
- "页面类型:生产页面 / 原型页面 / 营销页面 / 不涉及",
226
- "页面文案预算",
227
- "用户确认状态",
228
- "发现新增影响范围",
229
- "当前项目 AI 规则以 `xinyun-ai/` 为准",
230
- "旧 AI 文档、旧 docs、旧提示词、旧规则文件只作为历史线索,不作为执行依据",
231
- "规则优先级",
232
- "`xinyun-ai/` 当前正式规则",
233
- "当前文件系统事实",
234
- "历史会话记忆",
235
- "先识别、再分类、再接管",
236
- "可接管",
237
- "不接管",
238
- "待确认",
239
- "不创建自动迁移脚本",
240
- "中文需求解析",
241
- "用户原话",
242
- "任务类型至少包括",
243
- "高歧义表达",
244
- "优化一下",
245
- "处理一下",
246
- "高风险词",
247
- "订单、支付、退款",
248
- "最多追问 1-3 个关键问题",
249
- "ThinkPHP、uni-app、微信小程序",
250
- "涉及 SQL / 数据库改动时,必须单独输出 SQL 执行提醒",
251
- "商业逻辑",
252
- "xinyun-ai/global-review/",
253
- "首次极速初始化不强制创建 `xinyun-ai/global-review/`",
254
- "reviewId",
255
- "xinyun-ai/global-review/index.json",
256
- "Git 工作区与危险操作门禁",
257
- "单仓库",
258
- "多仓库",
259
- "混合仓库",
260
- "commit",
261
- "push",
262
- "rebase",
263
- "前端官方组件与 API 优先",
264
- "微信小程序",
265
- "uni.*",
266
- "Vue2 / Vue3",
267
- "React",
268
- "第三方库",
269
- "生产页面默认采用克制文案",
270
- "本页面用于",
271
- "智能、高效、便捷、全方位",
272
- "真实业务表达",
273
- "删除非必要说明后核心操作仍清楚",
274
- "明显 AI 话术",
275
- "不做无关全量扫描",
276
- "少复述规则",
277
- "双会话执行闭环(MVP)",
278
- "xinyun-ai/index/session-current.md",
279
- "xinyun-ai/handoffs/current-execution.md",
280
- "taskId",
281
- "executionId",
282
- "待主会话复核",
283
- "不得自动重试",
284
- "是否执行过高风险操作",
285
- "交付输出要求",
286
- "字段变更类任务还必须细分为",
287
- "字段影响审视 / 普通改动计划 / SQL 提醒 / 业务流程理解",
288
- "多仓库 Git 只读索引与端口映射",
289
- "最多记录 20 个仓库候选和 200 个相关目录 / 文件条目",
290
- "`repoRoot`",
291
- "`parentRepo`",
292
- "`kind`",
293
- "字段变更影响审视",
294
- "每个端口最多检查 300 个候选文件、1000 条匹配结果和 50 条证据记录",
295
- "排除 `node_modules`、`dist`、`build`、`vendor`",
296
- "CodeGraph 可用时,结构性影响优先使用 CodeGraph",
297
- "旧数据兼容方案",
298
- "未确认前不得执行 SQL、migration、seed、批量数据修复或接口兼容改动",
299
- "AI 项目团队与责任闭环",
300
- "xinyun-ai/team/",
301
- "roles.json",
302
- "members.json",
303
- "assignments.json",
304
- "responsibility-matrix.json",
305
- "file-ownership.json",
306
- "confirmations/<roleId>.md",
307
- "understandings/<roleId>.md",
308
- "capabilities.teamResponsibilityClosure: true",
309
- "roleCount=5",
310
- "confirmationCount=5",
311
- "status=pending-confirmation",
312
- "`createdAt`、`updatedAt` 必须存在且为 ISO 8601 时间",
313
- "memberId` 不得等于 `technicalApproverMemberId`",
314
- "status=paused",
315
- "pauseReason=out-of-scope",
316
- "paused-out-of-scope",
317
- ]);
318
-
319
- requireIncludes("init/xinyun-ai-init/templates/AGENTS.template.md", [
320
- "当前项目 AI 规则以 `xinyun-ai/` 为准",
321
- "规则优先级",
322
- "历史会话记忆不得覆盖当前文件系统事实",
323
- "先识别、再分类、再接管",
324
- "未确认内容不得直接写入正式规则",
325
- "任何代码、配置、数据库、依赖、构建脚本、测试逻辑、API 行为、UI 行为或业务流程修改前",
326
- "只有用户明确回复“确认执行”“可以修改”“按方案改”“同意”等类似内容后",
327
- "发现新增影响范围",
328
- "前端组件调用、框架 API 和交互能力优先使用官方组件",
329
- "页面类型必须标注为:生产页面 / 原型页面 / 营销页面 / 不涉及",
330
- "生产页面默认采用克制文案",
331
- "明显 AI 话术",
332
- "单仓库 / 多仓库 / 混合仓库 / 无 Git",
333
- "不得自动执行 `commit`、`tag`、`push`、`pull`、`merge`、`rebase`、`reset`、`checkout` 回滚或切分支",
334
- "双会话文件契约",
335
- "失败、中断、超时后不得自动重试",
336
- "中文需求解析与任务分型",
337
- "高歧义表达包括",
338
- "高风险词包括",
339
- "最多追问 1-3 个关键问题",
340
- "全局影响审视",
341
- "首次极速初始化不强制创建",
342
- "字段变更类任务必须细分为",
343
- "多仓库 Git 只读索引最多向下发现 4 层目录",
344
- "仓库索引必须包含 `repoRoot`",
345
- "ThinkPHP、uni-app、微信小程序轻量识别每个端口最多发现 3 层目录",
346
- "字段新增、删除、重命名、类型变化、含义变化",
347
- "xinyun-ai/team/",
348
- "teamResponsibilityClosure",
349
- "roleCount=5",
350
- "confirmationCount=5",
351
- "memberId` 不得等于 `technicalApproverMemberId`",
352
- "pauseReason=out-of-scope",
353
- ]);
354
-
355
- requireIncludes("init/xinyun-ai-init/templates/core-rules.template.md", [
356
- "标准改动计划",
357
- "前端改动模式:样式微调 / 新页面 / 页面重写 / 组件重构 / 不涉及",
358
- "规则优先级",
359
- "历史会话记忆不得覆盖当前文件系统事实",
360
- "先识别、再分类、再接管",
361
- "不创建自动迁移脚本",
362
- "中文需求解析格式",
363
- "用户原话",
364
- "任务类型至少包括",
365
- "高歧义表达包括",
366
- "高风险词包括",
367
- "最多追问 1-3 个关键问题",
368
- "页面类型:生产页面 / 原型页面 / 营销页面 / 不涉及",
369
- "页面文案预算",
370
- "发现新增影响范围",
371
- "有 CodeGraph 时,结构性问题优先使用 CodeGraph",
372
- "发现可复用经验时,先记录为候选经验",
373
- "前端官方组件与 API 优先",
374
- "uni.*",
375
- "Vue2 / Vue3",
376
- "React 官方组件模式",
377
- "生产页面默认采用克制文案",
378
- "本页面用于",
379
- "智能、高效、便捷、全方位",
380
- "真实业务表达",
381
- "删除非必要说明后核心操作仍清楚",
382
- "不做无关全量扫描",
383
- "少复述规则",
384
- "Git 工作区与危险操作门禁",
385
- "首次极速初始化不强制创建 `xinyun-ai/global-review/`",
386
- "`reviewId`",
387
- "xinyun-ai/global-review/index.json",
388
- "单仓库 / 多仓库 / 混合仓库 / 无 Git",
389
- "不得自动执行 `commit`、`tag`、`push`、`pull`、`merge`、`rebase`、`reset`、`checkout` 回滚或切分支",
390
- "双会话执行闭环(MVP)",
391
- "xinyun-ai/index/session-current.md",
392
- "xinyun-ai/handoffs/current-execution.md",
393
- "taskId",
394
- "executionId",
395
- "不得自动重试",
396
- "人工启动第二会话",
397
- "交付输出",
398
- "字段变更类任务必须细分为",
399
- "多仓库 Git 只读索引最多向下发现 4 层目录",
400
- "`repoRoot`、`path`、`workstream`、`kind`、`parentRepo`",
401
- "每个端口从端口根目录向下最多发现 3 层目录",
402
- "正向识别必须输出证据路径和证据类型",
403
- "字段变更影响审视",
404
- "每个端口最多检查 300 个候选文件、1000 条匹配结果和 50 条证据记录",
405
- "字段影响审视输出契约",
406
- "AI 项目团队与责任闭环",
407
- "project-owner",
408
- "project-product",
409
- "chief-engineer",
410
- "programmer",
411
- "test-reviewer",
412
- "capabilities.teamResponsibilityClosure: true",
413
- "roleCount=5",
414
- "confirmationCount=5",
415
- "`createdAt`、`updatedAt` 必须存在且为 ISO 8601 时间",
416
- "memberId` 不得等于 `technicalApproverMemberId`",
417
- "blockedReason=member-conflict",
418
- "blockedReason=approver-unavailable",
419
- "pauseReason=out-of-scope",
420
- "paused-out-of-scope",
421
- ]);
422
-
423
- requireIncludes("init/xinyun-ai-init/templates/current-task.template.md", [
424
- "前端改动模式",
425
- "中文需求解析",
426
- "用户原话",
427
- "任务类型",
428
- "风险词",
429
- "是否需要追问",
430
- "页面类型",
431
- "页面文案预算",
432
- "用户确认状态",
433
- "交付状态",
434
- "下一步动作",
435
- "字段任务分型",
436
- "字段专项路由",
437
- "多仓库 Git 只读索引",
438
- "字段影响审视",
439
- "团队责任闭环",
440
- "technicalApproverMemberId",
441
- "businessApproverMemberId",
442
- "publishAuthorizerMemberId",
443
- "预计更新文件目录",
444
- "实际更新文件目录",
445
- ]);
446
-
447
- requireIncludes("init/xinyun-ai-init/templates/project-index.template.json", [
448
- "single-project-single-active-task-main-session-plus-execution-session",
449
- "productionCopyMode",
450
- "conclusion-first",
451
- "legacyHandoff",
452
- "globalReview",
453
- "requirementParsing",
454
- "createOnFastInit",
455
- "frameworkEvidenceBudget",
456
- "gitRepositories",
457
- "fieldImpactReview",
458
- "fieldChangeRequirementRouting",
459
- "team",
460
- "roleCount",
461
- "confirmationCount",
462
- "pending-confirmation",
463
- ]);
464
-
465
- requireIncludes("init/xinyun-ai-init/rules/session-workbench.md", [
466
- "状态机至少包含",
467
- "失败、中断、超时后不得自动重试",
468
- "临时执行任务单建议结构",
469
- "执行交接单建议结构",
470
- "是否执行过高风险操作",
471
- "可接管、不接管、待确认",
472
- "中文需求解析结果",
473
- "全局影响审视摘要",
474
- "字段变更任务单还必须记录字段分类",
475
- "多仓库 Git 任务单还必须记录只读仓库索引",
476
- "字段影响审视交接",
477
- "团队责任任务单还必须记录需求负责人",
478
- "memberId` 等于 `technicalApproverMemberId`",
479
- "blockedReason=member-conflict",
480
- "blockedReason=approver-unavailable",
481
- "pauseReason=out-of-scope",
482
- "实际更新文件目录",
483
- ]);
484
-
485
- requireIncludes("init/xinyun-ai-init/templates/project-guide.template.md", [
486
- "规则优先级",
487
- "中文需求解析与任务分型",
488
- "全局影响审视",
489
- "待确认内容",
490
- "多仓库 Git 只读索引",
491
- "字段影响审视",
492
- "字段任务分型",
493
- "AI 项目团队与责任闭环",
494
- "角色数量",
495
- "职责确认记录数量",
496
- ]);
497
-
498
- requireIncludes("init/xinyun-ai-init/templates/project-check.template.md", [
499
- "规则入口优先级",
500
- "中文需求解析触发情况",
501
- "全局影响审视触发情况",
502
- "待确认内容",
503
- "多仓库 Git 只读索引",
504
- "字段变更任务分型与专项路由",
505
- "证据路径与证据类型",
506
- "字段影响审视",
507
- "AI 项目团队与责任闭环",
508
- "5 个 JSON 配置是否可解析",
509
- "自确认 memberId 冲突阻断",
510
- ]);
511
-
512
- requireIncludes("init/xinyun-ai-init/rules/init-rules.md", [
513
- "当前项目 AI 规则以 `xinyun-ai/` 为准",
514
- "当前项目未发现",
515
- "可接管、不接管、待确认",
516
- "首次极速初始化不强制创建",
517
- "最多追问 1-3 个关键问题",
518
- "多仓库 Git 只读索引最多发现 4 层目录",
519
- "字段新增、删除、重命名",
520
- "xinyun-ai/team/",
521
- "teamResponsibilityClosure",
522
- ]);
523
-
524
- requireIncludes("init/xinyun-ai-init/rules/upgrade-rules.md", [
525
- "规则优先级",
526
- "中文需求解析",
527
- "xinyun-ai/global-review/",
528
- "不自动迁移全部旧 AI 文档",
529
- "框架识别证据路径、证据类型",
530
- "多仓库 Git 只读索引字段",
531
- "字段影响审视",
532
- "xinyun-ai/team/",
533
- "teamResponsibilityClosure",
534
- "pauseReason=out-of-scope",
535
- ]);
536
-
537
- requireIncludes("init/xinyun-ai-init/rules/directory-self-completion.md", [
538
- "xinyun-ai/global-review/",
539
- "首次极速初始化不强制创建",
540
- "xinyun-ai/global-review/index.json",
541
- "`reviewId`",
542
- "端口框架线索",
543
- "多仓库 Git 结构",
544
- "字段审视记录",
545
- "xinyun-ai/team/",
546
- "index/project-index.json",
547
- "paused-out-of-scope",
548
- ]);
549
- }
550
-
551
- function verifyTestScenarios() {
552
- requireIncludes("test-scenarios/scenarios.md", [
553
- "1-133",
554
- "106",
555
- "## 40. v1.6-A",
556
- "## 53. v1.6 tarball",
557
- "## 55. verify:rules",
558
- "## 59. ThinkPHP",
559
- "## 64. HTML",
560
- "## 69. verify:rules JSON schema",
561
- "## 71. v1.7.1 主任务命名",
562
- "## 87. v1.7.1 普通咨询和版本回归",
563
- "## 89. v1.7.3 Codex 真实角色会话创建",
564
- "## 96. v1.7.3 普通咨询边界",
565
- "## 97. Skill",
566
- ]);
567
-
568
- requireIncludes("test-scenarios/README.md", [
569
- "pm_zhousl-xinyun-ai-init-1.10.1.tgz",
570
- "1-133",
571
- "119",
572
- "npm run verify:rules",
573
- "v1.7.2-scenarios.md",
574
- "v1.7.3-scenarios.md",
575
- ]);
576
-
577
- requireIncludes("test-scenarios/v1.7.1-scenarios.md", [
578
- "主任务命名",
579
- "角色登记与执行资格分离",
580
- "归档原子性和任务索引",
581
- "CodeGraph初始化授权边界",
582
- "CodeGraph记录与失败矩阵",
583
- "普通咨询边界",
584
- ]);
585
-
586
- requireIncludes("test-scenarios/v1.7.2-scenarios.md", [
587
- "role-execution",
588
- "activeTaskIds",
589
- "executableTaskIds",
590
- "固定优先级",
591
- "幂等补建",
592
- "补建失败和索引恢复",
593
- ]);
594
-
595
- requireIncludes("test-scenarios/v1.7.3-scenarios.md", [
596
- "真实角色子会话创建",
597
- "provider=codex",
598
- "sessionStatus=onboarding",
599
- "taskId + roleId + provider + targetVersion",
600
- "local-degraded-no-fake-session-id",
601
- "created-but-writeback-failed",
602
- "单角色失败不影响其他角色",
603
- "普通咨询边界",
604
- ]);
605
- }
606
- function verifyFrameworkRules() {
607
- const required = [
608
- "init/xinyun-ai-init/rules/frameworks/README.md",
609
- "init/xinyun-ai-init/rules/frameworks/backend/php/thinkphp.md",
610
- "init/xinyun-ai-init/rules/frameworks/frontend/uni-app.md",
611
- "init/xinyun-ai-init/rules/frameworks/frontend/wechat-miniprogram.md",
612
- ];
613
-
614
- for (const file of required) {
615
- requireFile(file);
616
- }
617
-
618
- requireIncludes("init/xinyun-ai-init/rules/frameworks/backend/php/thinkphp.md", [
619
- "topthink/framework",
620
- "think\\facade",
621
- "最多发现 3 层目录",
622
- "最多读取 20 个关键文件",
623
- "证据路径和证据类型",
624
- "未在项目中发现",
625
- "状态未知",
626
- "覆盖范围:部分",
627
- ]);
628
- requireIncludes("init/xinyun-ai-init/rules/frameworks/frontend/uni-app.md", [
629
- "pages.json",
630
- "vite-plugin-uni",
631
- "最多发现 3 层目录",
632
- "最多读取 20 个关键文件",
633
- "证据路径和证据类型",
634
- "未在项目中发现",
635
- "状态未知",
636
- "覆盖范围:部分",
637
- "不把原生微信小程序规则反向套到 uni-app",
638
- ]);
639
- requireIncludes("init/xinyun-ai-init/rules/frameworks/frontend/wechat-miniprogram.md", [
640
- "project.config.json",
641
- ".wxml",
642
- "最多发现 3 层目录",
643
- "最多读取 20 个关键文件",
644
- "证据路径和证据类型",
645
- "未在项目中发现",
646
- "状态未知",
647
- "覆盖范围:部分",
648
- "不把 uni-app 规则反向套到原生微信小程序",
649
- ]);
650
- requireIncludes("init/xinyun-ai-init/rules/frameworks/README.md", [
651
- "证据路径和证据类型",
652
- "发现预算:目录深度 3 层、关键文件 20 个",
653
- "未在项目中发现",
654
- "状态未知",
655
- "覆盖范围:部分",
656
- ]);
657
- }
658
-
659
- function verifyTeamTemplates() {
660
- const roleIds = ["project-owner", "project-product", "chief-engineer", "programmer", "test-reviewer"];
661
- const teamFiles = [
662
- "init/xinyun-ai-init/templates/team/README.md",
663
- "init/xinyun-ai-init/templates/team/roles.json",
664
- "init/xinyun-ai-init/templates/team/members.json",
665
- "init/xinyun-ai-init/templates/team/assignments.json",
666
- "init/xinyun-ai-init/templates/team/responsibility-matrix.json",
667
- "init/xinyun-ai-init/templates/team/file-ownership.json",
668
- ];
669
-
670
- for (const file of teamFiles) {
671
- requireFile(file);
672
- }
673
-
674
- for (const roleId of roleIds) {
675
- requireFile(`init/xinyun-ai-init/templates/team/confirmations/${roleId}.md`);
676
- requireFile(`init/xinyun-ai-init/templates/team/understandings/${roleId}.md`);
677
- }
678
-
679
- const manifestTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
680
- const projectIndexTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
681
- const roles = JSON.parse(readText("init/xinyun-ai-init/templates/team/roles.json"));
682
- const members = JSON.parse(readText("init/xinyun-ai-init/templates/team/members.json"));
683
- const assignments = JSON.parse(readText("init/xinyun-ai-init/templates/team/assignments.json"));
684
- const matrix = JSON.parse(readText("init/xinyun-ai-init/templates/team/responsibility-matrix.json"));
685
- const ownership = JSON.parse(readText("init/xinyun-ai-init/templates/team/file-ownership.json"));
686
-
687
- addCheck(
688
- "manifest capabilities 包含 teamResponsibilityClosure",
689
- manifestTemplate.capabilities && manifestTemplate.capabilities.teamResponsibilityClosure === true,
690
- "manifest.template.json 未声明 teamResponsibilityClosure"
691
- );
692
-
693
- const expectedTeamPaths = {
694
- directory: "xinyun-ai/team/",
695
- roles: "xinyun-ai/team/roles.json",
696
- members: "xinyun-ai/team/members.json",
697
- assignments: "xinyun-ai/team/assignments.json",
698
- responsibilityMatrix: "xinyun-ai/team/responsibility-matrix.json",
699
- fileOwnership: "xinyun-ai/team/file-ownership.json",
700
- understandingsDirectory: "xinyun-ai/team/understandings/",
701
- confirmationsDirectory: "xinyun-ai/team/confirmations/",
702
- };
703
-
704
- for (const [key, value] of Object.entries(expectedTeamPaths)) {
705
- addCheck(
706
- `manifest team 路径 ${key}`,
707
- manifestTemplate.team && manifestTemplate.team[key] === value,
708
- `manifest team.${key} 应为 ${value}`
709
- );
710
- addCheck(
711
- `project-index team 路径 ${key}`,
712
- projectIndexTemplate.team &&
713
- projectIndexTemplate.team.paths &&
714
- projectIndexTemplate.team.paths[key] === value,
715
- `project-index team.paths.${key} 应为 ${value}`
716
- );
717
- }
718
-
719
- addCheck("project-index team enabled", projectIndexTemplate.team && projectIndexTemplate.team.enabled === true);
720
- addCheck("project-index team roleCount=5", projectIndexTemplate.team && projectIndexTemplate.team.roleCount === 5);
721
- addCheck("project-index team confirmationCount=5", projectIndexTemplate.team && projectIndexTemplate.team.confirmationCount === 5);
722
- addCheck("project-index team status=pending-confirmation", projectIndexTemplate.team && projectIndexTemplate.team.status === "pending-confirmation");
723
-
724
- const actualRoleIds = Array.isArray(roles.roles) ? roles.roles.map((role) => role.roleId) : [];
725
- addCheck("roles.json 包含 5 个角色", actualRoleIds.length === 5, `当前角色数 ${actualRoleIds.length}`);
726
- addCheck("roles.json roleId 全局唯一", new Set(actualRoleIds).size === actualRoleIds.length, "roleId 存在重复");
727
-
728
- for (const roleId of roleIds) {
729
- addCheck(`roles.json 包含角色 ${roleId}`, actualRoleIds.includes(roleId), "缺少默认角色");
730
- }
731
-
732
- const memberIds = Array.isArray(members.members) ? members.members.map((member) => member.memberId) : [];
733
- addCheck("members.json 包含 5 个成员槽位", memberIds.length === 5, `当前成员槽位 ${memberIds.length}`);
734
- addCheck("members.json memberId 全局唯一", new Set(memberIds).size === memberIds.length, "memberId 存在重复");
735
- addCheck(
736
- "members.json 未绑定时 personId/sessionId 为 null",
737
- Array.isArray(members.members) && members.members.every((member) => member.personId === null && member.sessionId === null),
738
- "未绑定成员不得虚构 personId/sessionId"
739
- );
740
-
741
- addCheck("assignments.json 状态包含 paused", assignments.statusEnum && assignments.statusEnum.includes("paused"));
742
- addCheck("assignments.json 状态包含 blocked", assignments.statusEnum && assignments.statusEnum.includes("blocked"));
743
- addCheck("assignments.json pauseReason 包含 out-of-scope", assignments.pauseReasonEnum && assignments.pauseReasonEnum.includes("out-of-scope"));
744
- addCheck("assignments.json blockedReason 包含 member-conflict", assignments.blockedReasonEnum && assignments.blockedReasonEnum.includes("member-conflict"));
745
- addCheck("assignments.json blockedReason 包含 approver-unavailable", assignments.blockedReasonEnum && assignments.blockedReasonEnum.includes("approver-unavailable"));
746
- addCheck(
747
- "assignments.json 包含 memberId 自确认冲突规则",
748
- typeof assignments.memberConflictRule === "string" && assignments.memberConflictRule.includes("technicalApproverMemberId"),
749
- "缺少成员级冲突规则"
750
- );
751
-
752
- const matrixRoleIds = Array.isArray(matrix.matrix) ? matrix.matrix.map((item) => item.roleId) : [];
753
- addCheck("responsibility-matrix.json 包含 5 条职责矩阵", matrixRoleIds.length === 5, `当前矩阵数 ${matrixRoleIds.length}`);
754
- addCheck(
755
- "chief-engineer 默认技术确认候选为空",
756
- Array.isArray(matrix.matrix) &&
757
- matrix.matrix.some((item) => item.roleId === "chief-engineer" && item.technicalApproverRoleId === null),
758
- "总工不得默认自指技术确认"
759
- );
760
- addCheck(
761
- "programmer 禁止最终确认和发布授权",
762
- Array.isArray(matrix.matrix) &&
763
- matrix.matrix.some((item) => item.roleId === "programmer" && item.forbiddenActions.includes("technical-final-approval") && item.forbiddenActions.includes("publish-authorization")),
764
- "程序员不得担任技术、业务或发布最终确认人"
765
- );
766
-
767
- addCheck("file-ownership pathType 包含 file", ownership.pathTypeEnum && ownership.pathTypeEnum.includes("file"));
768
- addCheck("file-ownership pathType 包含 directory", ownership.pathTypeEnum && ownership.pathTypeEnum.includes("directory"));
769
- addCheck("file-ownership pathType 包含 glob", ownership.pathTypeEnum && ownership.pathTypeEnum.includes("glob"));
770
- addCheck(
771
- "file-ownership 包含 out-of-scope 暂停规则",
772
- ownership.recordContract && ownership.recordContract.outOfScopeRule && ownership.recordContract.outOfScopeRule.includes("pauseReason=out-of-scope"),
773
- "缺少超范围暂停规则"
774
- );
775
-
776
- for (const roleId of roleIds) {
777
- const confirmationPath = `init/xinyun-ai-init/templates/team/confirmations/${roleId}.md`;
778
- const understandingPath = `init/xinyun-ai-init/templates/team/understandings/${roleId}.md`;
779
- const confirmationContent = readText(confirmationPath);
780
- const understandingContent = readText(understandingPath);
781
-
782
- requireIncludes(confirmationPath, [
783
- `roleId:${roleId}`,
784
- "status:pending",
785
- "memberId:null",
786
- "confirmedBy:null",
787
- "confirmedAt:null",
788
- "createdAt:",
789
- "updatedAt:",
790
- ]);
791
- addCheck(
792
- `${confirmationPath} createdAt 为 ISO 8601`,
793
- isIso8601Utc(markdownFieldValue(confirmationContent, "createdAt")),
794
- "createdAt 不得为空,且必须为 ISO 8601 UTC 时间"
795
- );
796
- addCheck(
797
- `${confirmationPath} updatedAt 为 ISO 8601`,
798
- isIso8601Utc(markdownFieldValue(confirmationContent, "updatedAt")),
799
- "updatedAt 不得为空,且必须为 ISO 8601 UTC 时间"
800
- );
801
-
802
- requireIncludes(understandingPath, [
803
- `roleId:${roleId}`,
804
- "status:pending",
805
- "executionEligible:false",
806
- "evidence:",
807
- "coverage:",
808
- "createdAt:",
809
- "updatedAt:",
810
- ]);
811
- addCheck(
812
- `${understandingPath} createdAt 为 ISO 8601`,
813
- isIso8601Utc(markdownFieldValue(understandingContent, "createdAt")),
814
- "createdAt 不得为空,且必须为 ISO 8601 UTC 时间"
815
- );
816
- addCheck(
817
- `${understandingPath} updatedAt 为 ISO 8601`,
818
- isIso8601Utc(markdownFieldValue(understandingContent, "updatedAt")),
819
- "updatedAt 不得为空,且必须为 ISO 8601 UTC 时间"
820
- );
821
- }
822
- }
823
-
824
- function verifyV16Contracts() {
825
- const requiredTemplates = [
826
- "init/xinyun-ai-init/templates/init-result.template.json",
827
- "init/xinyun-ai-init/templates/task-lock.template.json",
828
- "init/xinyun-ai-init/templates/task-history.template.md",
829
- "init/xinyun-ai-init/templates/task-result.template.json",
830
- "init/xinyun-ai-init/templates/managed-baseline.template.json",
831
- "init/xinyun-ai-init/templates/capabilities.template.json",
832
- ];
833
-
834
- for (const file of requiredTemplates) {
835
- requireFile(file);
836
- }
837
-
838
- requireIncludes("bin/xinyun-ai-init.js", [
839
- "update-check.json",
840
- "lastNotifiedVersion",
841
- "lastNotifiedAt",
842
- "24 hours",
843
- "After upgrading the npm package",
844
- "XDG_CACHE_HOME",
845
- "LOCALAPPDATA",
846
- ]);
847
-
848
- requireIncludes("init/xinyun-ai-init/README.md", [
849
- "当前规则版本:`1.9.0`",
850
- "v1.6 初始化任务、幂等恢复与结果记录",
851
- "xinyun-ai/tasks/.idempotency/",
852
- "xinyun-ai/init-result.json",
853
- "xinyun-ai/task-lock.json",
854
- "workspace-initialization",
855
- "workspace-upgrade",
856
- "idempotencyKey",
857
- "JCS",
858
- "normalizedEntryHash",
859
- "normalizedRequestHash",
860
- "businessCodeChanged.value=no",
861
- "task.status",
862
- "upgrade.status",
863
- "lock.status",
864
- "baselineHash",
865
- "templateHash",
866
- "both-changed",
867
- "conflict-pending",
868
- "能力检测证据",
869
- "fallbackPlan",
870
- "releasedBy",
871
- "releasedAt",
872
- "releaseReason",
873
- "sensitiveScanStatus=unknown",
874
- "[REDACTED]",
875
- "24 小时",
876
- "update-check.json",
877
- "HTML 整站转微信小程序或 uni-app 不进入 v1.6.0",
878
- ]);
879
-
880
- requireIncludes("init/xinyun-ai-init/templates/AGENTS.template.md", [
881
- "v1.6 初始化任务、恢复、升级和安全控制",
882
- "xinyun-ai/init-result.json",
883
- "xinyun-ai/task-lock.json",
884
- "idempotencyKey",
885
- "workspaceScope=xinyun-ai-control",
886
- "businessCodeChanged.value",
887
- "baselineHash",
888
- "capability.status",
889
- "lock.status",
890
- "[REDACTED]",
891
- ]);
892
-
893
- requireIncludes("init/xinyun-ai-init/templates/core-rules.template.md", [
894
- "v1.6 初始化任务、幂等恢复与结果记录",
895
- "xinyun-ai/tasks/.idempotency/",
896
- "task.status",
897
- "result.status",
898
- "upgrade.status",
899
- "lock.status",
900
- "idempotencyKey",
901
- "JCS",
902
- "businessCodeChanged.value=no",
903
- "baselineHash",
904
- "templateHash",
905
- "package-only",
906
- "user-only",
907
- "reconciled",
908
- "both-changed",
909
- "task-lock.json",
910
- "releasedBy",
911
- "capabilityId",
912
- "fallbackPlan",
913
- "[REDACTED]",
914
- ]);
915
-
916
- requireIncludes("init/xinyun-ai-init/templates/current-task.template.md", [
917
- "idempotencyKey",
918
- "task.status",
919
- "upgrade.status",
920
- "lock.status",
921
- "result.status",
922
- "init-result.json",
923
- "businessCodeChanged",
924
- "baselineHash",
925
- "capability.status",
926
- "sensitiveScanStatus",
927
- ]);
928
-
929
- requireIncludes("init/xinyun-ai-init/templates/project-index.template.json", [
930
- "tasking",
931
- "idempotencyDirectory",
932
- "initResult",
933
- "taskLock",
934
- "managedBaseline",
935
- "capabilities",
936
- "stateMachine",
937
- ]);
938
-
939
- requireIncludes("init/xinyun-ai-init/templates/project-guide.template.md", [
940
- "idempotencyKey",
941
- "task.status",
942
- "init-result.json",
943
- "task-lock.json",
944
- "businessCodeChanged",
945
- "managed-baseline.json",
946
- "capability.status",
947
- "sensitiveScanStatus",
948
- ]);
949
-
950
- requireIncludes("init/xinyun-ai-init/templates/project-check.template.md", [
951
- "v1.6 统一初始化任务",
952
- "init-result.json",
953
- "task-lock.json",
954
- "v1.6 升级差异与基线",
955
- "managed-baseline.json",
956
- "v1.6 能力检测与降级",
957
- "capabilities.json",
958
- "v1.6 锁、可信边界与脱敏",
959
- ]);
960
-
961
- requireIncludes("init/xinyun-ai-init/rules/init-rules.md", [
962
- "xinyun-ai/tasks/.idempotency/",
963
- "init-result.json",
964
- "task-lock.json",
965
- "idempotencyKey",
966
- "businessCodeChanged.value",
967
- "[REDACTED]",
968
- "HTML 整站转微信小程序或 uni-app 不进入 v1.6.0",
969
- ]);
970
-
971
- requireIncludes("init/xinyun-ai-init/rules/upgrade-rules.md", [
972
- "v1.6 升级差异与冲突保护",
973
- "baselineHash",
974
- "templateHash",
975
- "both-changed",
976
- "conflict-pending",
977
- "task-lock.json",
978
- "businessCodeChanged.value=no",
979
- "[REDACTED]",
980
- ]);
981
-
982
- requireIncludes("init/xinyun-ai-init/rules/directory-self-completion.md", [
983
- "xinyun-ai/tasks/.idempotency/",
984
- "init-result.json",
985
- "task-lock.json",
986
- "managed-baseline.json",
987
- "capabilities.json",
988
- "baselineHash",
989
- "capabilityId",
990
- "sensitiveScanStatus=unknown",
991
- ]);
992
-
993
- requireIncludes("init/xinyun-ai-init/rules/session-workbench.md", [
994
- "idempotencyKey",
995
- "init-result.json",
996
- "businessCodeChanged.value",
997
- "task-lock.json",
998
- "lock audit",
999
- "[REDACTED]",
1000
- ]);
1001
-
1002
- const manifestTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
1003
- const projectIndexTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
1004
- const initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
1005
- const taskLock = JSON.parse(readText("init/xinyun-ai-init/templates/task-lock.template.json"));
1006
- const capabilityTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/capabilities.template.json"));
1007
-
1008
- const capabilityFlags = [
1009
- "workspaceTaskHistory",
1010
- "idempotentInitialization",
1011
- "upgradeConflictProtection",
1012
- "capabilityDetectionEvidence",
1013
- "localTaskLock",
1014
- "sensitiveRedaction",
1015
- ];
1016
-
1017
- for (const flag of capabilityFlags) {
1018
- addCheck(
1019
- `manifest capabilities 包含 ${flag}`,
1020
- manifestTemplate.capabilities && manifestTemplate.capabilities[flag] === true,
1021
- `manifest.template.json 未声明 ${flag}`
1022
- );
1023
- }
1024
-
1025
- const taskingPaths = {
1026
- currentTask: "xinyun-ai/current-task.md",
1027
- tasksDirectory: "xinyun-ai/tasks/",
1028
- idempotencyDirectory: "xinyun-ai/tasks/.idempotency/",
1029
- initResult: "xinyun-ai/init-result.json",
1030
- taskLock: "xinyun-ai/task-lock.json",
1031
- managedBaseline: "xinyun-ai/index/managed-baseline.json",
1032
- capabilities: "xinyun-ai/index/capabilities.json",
1033
- };
1034
-
1035
- for (const [key, value] of Object.entries(taskingPaths)) {
1036
- addCheck(
1037
- `manifest tasking 路径 ${key}`,
1038
- manifestTemplate.tasking && manifestTemplate.tasking[key] === value,
1039
- `manifest tasking.${key} 应为 ${value}`
1040
- );
1041
- addCheck(
1042
- `project-index tasking 路径 ${key}`,
1043
- projectIndexTemplate.tasking && projectIndexTemplate.tasking[key] === value,
1044
- `project-index tasking.${key} 应为 ${value}`
1045
- );
1046
- }
1047
-
1048
- addCheck("init-result mode 为 initialization", initResult.mode === "initialization");
1049
- addCheck("init-result targetVersion=current", initResult.targetVersion === CURRENT_VERSION);
1050
- addCheck("init-result businessCodeChanged 初始为 unknown", initResult.businessCodeChanged && initResult.businessCodeChanged.value === "unknown");
1051
- addCheck("task-lock scope=xinyun-ai-control", taskLock.scope === "xinyun-ai-control");
1052
- addCheck("task-lock audit 包含 released", Array.isArray(taskLock.audit) && taskLock.audit.some((item) => item.action === "released"));
1053
- addCheck(
1054
- "capabilities.template 包含 fallbackPlan",
1055
- Array.isArray(capabilityTemplate.capabilities) &&
1056
- capabilityTemplate.capabilities.some((item) => typeof item.fallbackPlan === "string" && item.fallbackPlan.includes("静态分析")),
1057
- "能力模板缺少降级方案"
1058
- );
1059
- }
1060
-
1061
- function verifyV17Contracts() {
1062
- const packageJson = JSON.parse(readText("package.json"));
1063
- const manifestTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
1064
- const projectIndexTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
1065
- const frameworkProfile = JSON.parse(readText("init/xinyun-ai-init/templates/framework-profile.template.json"));
1066
- const htmlMigration = JSON.parse(readText("init/xinyun-ai-init/templates/html-migration-record.template.json"));
1067
-
1068
- addCheck(
1069
- "package.json scripts contains verify:rules",
1070
- packageJson.scripts && packageJson.scripts["verify:rules"] === "node ./scripts/verify-rules-package.js",
1071
- "missing verify:rules package consistency command"
1072
- );
1073
-
1074
- const requiredTemplates = [
1075
- "init/xinyun-ai-init/templates/framework-profile.template.md",
1076
- "init/xinyun-ai-init/templates/framework-profile.template.json",
1077
- "init/xinyun-ai-init/templates/html-migration-scope.template.md",
1078
- "init/xinyun-ai-init/templates/html-migration-compatibility-matrix.template.md",
1079
- "init/xinyun-ai-init/templates/html-migration-route-map.template.md",
1080
- "init/xinyun-ai-init/templates/html-migration-asset-map.template.md",
1081
- "init/xinyun-ai-init/templates/html-migration-pilot-plan.template.md",
1082
- "init/xinyun-ai-init/templates/html-migration-open-issues.template.md",
1083
- "init/xinyun-ai-init/templates/html-migration-record.template.json",
1084
- "scripts/verify-rules-package.js",
1085
- "test-scenarios/v1.7.1-scenarios.md",
1086
- ];
1087
-
1088
- for (const file of requiredTemplates) {
1089
- requireFile(file);
1090
- }
1091
-
1092
- for (const flag of [
1093
- "rulePackageConsistencyCheck",
1094
- "technologyStackProfile",
1095
- "thinkphpDeepProfile",
1096
- "htmlToClientMigrationPreparation",
1097
- ]) {
1098
- addCheck(
1099
- `manifest capabilities contains ${flag}`,
1100
- manifestTemplate.capabilities && manifestTemplate.capabilities[flag] === true,
1101
- `manifest.template.json missing ${flag}`
1102
- );
1103
- }
1104
-
1105
- const frameworkPaths = {
1106
- directory: "xinyun-ai/frameworks/",
1107
- markdown: "xinyun-ai/frameworks/framework-profile.md",
1108
- json: "xinyun-ai/frameworks/framework-profile.json",
1109
- };
1110
- for (const [key, value] of Object.entries(frameworkPaths)) {
1111
- addCheck(
1112
- `manifest frameworkProfile path ${key}`,
1113
- manifestTemplate.frameworkProfile && manifestTemplate.frameworkProfile[key] === value,
1114
- `manifest frameworkProfile.${key} should be ${value}`
1115
- );
1116
- }
1117
-
1118
- const htmlPaths = {
1119
- directory: "xinyun-ai/migrations/html-to-client/",
1120
- scope: "xinyun-ai/migrations/html-to-client/migration-scope.md",
1121
- compatibilityMatrix: "xinyun-ai/migrations/html-to-client/compatibility-matrix.md",
1122
- routeMap: "xinyun-ai/migrations/html-to-client/route-map.md",
1123
- assetMap: "xinyun-ai/migrations/html-to-client/asset-map.md",
1124
- pilotPlan: "xinyun-ai/migrations/html-to-client/pilot-plan.md",
1125
- openIssues: "xinyun-ai/migrations/html-to-client/open-issues.md",
1126
- recordJson: "xinyun-ai/migrations/html-to-client/migration-record.json",
1127
- };
1128
- for (const [key, value] of Object.entries(htmlPaths)) {
1129
- addCheck(
1130
- `manifest htmlMigration path ${key}`,
1131
- manifestTemplate.htmlMigration && manifestTemplate.htmlMigration[key] === value,
1132
- `manifest htmlMigration.${key} should be ${value}`
1133
- );
1134
- }
1135
-
1136
- addCheck("project-index frameworkProfile enabled", projectIndexTemplate.frameworkProfile && projectIndexTemplate.frameworkProfile.enabled === true);
1137
- addCheck("project-index htmlMigration enabled", projectIndexTemplate.htmlMigration && projectIndexTemplate.htmlMigration.enabled === true);
1138
- addCheck("framework profile language object exists", frameworkProfile.language && typeof frameworkProfile.language === "object");
1139
- addCheck("framework profile runtime object exists", frameworkProfile.runtime && typeof frameworkProfile.runtime === "object");
1140
- addCheck("framework profile platform object exists", frameworkProfile.platform && typeof frameworkProfile.platform === "object");
1141
- addCheck("framework profile frameworkStatus enum default", frameworkProfile.frameworkStatus === "unknown");
1142
- addCheck("framework profile moduleStatus default", frameworkProfile.moduleStatus === "not-loaded");
1143
- addCheck("framework profile activation default", frameworkProfile.activation === "not-loaded");
1144
- addCheck("framework profile deep budget depth=5", frameworkProfile.budgets && frameworkProfile.budgets.deep && frameworkProfile.budgets.deep.maxDepthPerWorkstream === 5);
1145
- addCheck("framework profile deep budget files=80", frameworkProfile.budgets && frameworkProfile.budgets.deep && frameworkProfile.budgets.deep.maxKeyFilesPerWorkstream === 80);
1146
- addCheck("framework profile deep budget evidence=100", frameworkProfile.budgets && frameworkProfile.budgets.deep && frameworkProfile.budgets.deep.maxEvidence === 100);
1147
- addCheck("html migration status default planned", htmlMigration.status === "planned");
1148
- addCheck("html migration coverage default unknown", htmlMigration.coverage === "unknown");
1149
- addCheck("html migration budget pages=20", htmlMigration.budgets && htmlMigration.budgets.maxPages === 20);
1150
- addCheck("html migration budget files=200", htmlMigration.budgets && htmlMigration.budgets.maxRelatedFiles === 200);
1151
- addCheck("html migration budget evidence=100", htmlMigration.budgets && htmlMigration.budgets.maxEvidence === 100);
1152
- addCheck("html migration pilot requires separate confirmation", htmlMigration.pilotPlan && htmlMigration.pilotPlan.requiresSeparateConfirmation === true);
1153
-
1154
- requireIncludes("init/xinyun-ai-init/README.md", [
1155
- "当前规则版本:`1.9.0`",
1156
- "v1.7 规则包一致性检查与 verify:rules",
1157
- "frameworkStatus=confirmed/inferred/not-found/unknown/detected-unsupported",
1158
- "v1.7 深化预算:5 层目录、80 个关键文件、100 条证据",
1159
- "HTML 迁移到微信小程序/uni-app落地准备",
1160
- "decision=direct-map/rewrite-required/backend-required/unsupported/pending/unknown",
1161
- "status=planned/assessing/partial/blocked/paused/completed",
1162
- "coverage=full/partial/unknown",
1163
- "pauseReason=out-of-scope",
1164
- ]);
1165
-
1166
- requireIncludes("init/xinyun-ai-init/templates/core-rules.template.md", [
1167
- "v1.7 规则包一致性检查与 verify:rules",
1168
- "`language`、`runtime`、`platform`、`framework` 必须独立记录",
1169
- "v1.7 HTML 迁移落地准备",
1170
- "scope/unverifiedScope",
1171
- ]);
1172
-
1173
- requireIncludes("test-scenarios/scenarios.md", [
1174
- "当前必测场景为 1-133",
1175
- "当前观察场景为 106 和 119",
1176
- "## 55. verify:rules 正常通过",
1177
- "## 69. verify:rules JSON schema 和重复执行",
1178
- "## 97. Skill 触发测试",
1179
- ]);
1180
-
1181
- requireIncludes("test-scenarios/README.md", [
1182
- "pm_zhousl-xinyun-ai-init-1.10.1.tgz",
1183
- "当前 v1.8 既有必测场景为 `scenarios.md` 的 1-105;v1.9 新增 107-118",
1184
- "当前观察场景为 `scenarios.md` 的 106 和 119",
1185
- "npm run verify:rules",
1186
- ]);
1187
- }
1188
-
1189
- function verifyV171Contracts() {
1190
- const manifestTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
1191
- const projectIndexTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
1192
- const initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
1193
- const taskIndex = JSON.parse(readText("init/xinyun-ai-init/templates/task-index.template.json"));
1194
- const archiveTransaction = JSON.parse(readText("init/xinyun-ai-init/templates/archive-transaction.template.json"));
1195
-
1196
- const requiredTemplates = [
1197
- "init/xinyun-ai-init/templates/task-index.template.json",
1198
- "init/xinyun-ai-init/templates/task-main.template.md",
1199
- "init/xinyun-ai-init/templates/role-subtask.template.md",
1200
- "init/xinyun-ai-init/templates/archive-transaction.template.json",
1201
- "test-scenarios/v1.7.1-scenarios.md",
1202
- ];
1203
- for (const file of requiredTemplates) requireFile(file);
1204
-
1205
- for (const flag of ["namedInitializationTaskTree", "taskArchiveTransactions", "codeGraphRequiredInitialization"]) {
1206
- addCheck(
1207
- `manifest capabilities 包含 ${flag}`,
1208
- manifestTemplate.capabilities && manifestTemplate.capabilities[flag] === true,
1209
- `manifest.template.json 未声明 ${flag}`
1210
- );
1211
- }
1212
-
1213
- const taskingPaths = {
1214
- taskIndex: "xinyun-ai/tasks/task-index.json",
1215
- archiveDirectory: "xinyun-ai/tasks/archive/",
1216
- archiveTransactionsDirectory: "xinyun-ai/tasks/.archive-transactions/",
1217
- archiveTempDirectory: "xinyun-ai/tasks/.archive-tmp/",
1218
- };
1219
- for (const [key, value] of Object.entries(taskingPaths)) {
1220
- addCheck(`manifest v1.7.1 tasking 路径 ${key}`, manifestTemplate.tasking && manifestTemplate.tasking[key] === value, `manifest tasking.${key} 应为 ${value}`);
1221
- addCheck(`project-index v1.7.1 tasking 路径 ${key}`, projectIndexTemplate.tasking && projectIndexTemplate.tasking[key] === value, `project-index tasking.${key} 应为 ${value}`);
1222
- }
1223
-
1224
- addCheck("manifest taskTree enabled", manifestTemplate.taskTree && manifestTemplate.taskTree.enabled === true, "manifest.taskTree.enabled 应为 true");
1225
- addCheck("project-index taskTree enabled", projectIndexTemplate.taskTree && projectIndexTemplate.taskTree.enabled === true, "project-index.taskTree.enabled 应为 true");
1226
- addCheck("taskTree 主任务标题模式", manifestTemplate.taskTree && manifestTemplate.taskTree.mainTaskTitlePattern === "项目初始化:<项目显示名>", "主任务标题模式不一致");
1227
- addCheck("taskTree 角色任务数为 5", manifestTemplate.taskTree && manifestTemplate.taskTree.roleTaskCount === 5, "roleTaskCount 应为 5");
1228
-
1229
- addCheck("task-index activeTaskIds 数组", Array.isArray(taskIndex.activeTaskIds), "activeTaskIds 必须是数组");
1230
- addCheck("task-index executableTaskIds 数组", Array.isArray(taskIndex.executableTaskIds), "executableTaskIds 必须是数组");
1231
- addCheck("task-index archivedTaskIds 数组", Array.isArray(taskIndex.archivedTaskIds), "archivedTaskIds 必须是数组");
1232
- addCheck("task-index idle status", taskIndex.idleCurrentTask && taskIndex.idleCurrentTask.status === "idle", "idleCurrentTask.status 应为 idle");
1233
- addCheck("task-index idle taskId null", taskIndex.idleCurrentTask && taskIndex.idleCurrentTask.taskId === null, "idleCurrentTask.taskId 应为 null");
1234
- addCheck("task-index idle title", taskIndex.idleCurrentTask && taskIndex.idleCurrentTask.title === "暂无待执行任务", "idle 标题不一致");
1235
-
1236
- const phases = ["prepared", "validated", "moved", "indexed", "committed", "recovery-required", "blocked"];
1237
- addCheck("archive transaction phase prepared", archiveTransaction.phase === "prepared", "归档事务默认 phase 应为 prepared");
1238
- addCheck("archive transaction phase enum 完整", phases.every((phase) => archiveTransaction.phaseEnum && archiveTransaction.phaseEnum.includes(phase)), "归档事务 phaseEnum 缺少必需状态");
1239
-
1240
- const codeGraphStatuses = ["initialized", "healthy", "missing", "unavailable", "permission-denied", "failed", "unknown"];
1241
- addCheck("manifest CodeGraph required", manifestTemplate.codeGraphRequired && manifestTemplate.codeGraphRequired.required === true, "manifest CodeGraph required 应为 true");
1242
- addCheck("project-index CodeGraph required", projectIndexTemplate.codeGraphRequired && projectIndexTemplate.codeGraphRequired.required === true, "project-index CodeGraph required 应为 true");
1243
- addCheck("manifest CodeGraph status enum 完整", codeGraphStatuses.every((status) => manifestTemplate.codeGraphRequired && manifestTemplate.codeGraphRequired.statusEnum.includes(status)), "CodeGraph statusEnum 缺少状态");
1244
- addCheck("manifest CodeGraph command", manifestTemplate.codeGraphRequired && manifestTemplate.codeGraphRequired.command === "codegraph init -i", "CodeGraph command 应为 codegraph init -i");
1245
- addCheck("init-result CodeGraph required", initResult.codeGraph && initResult.codeGraph.required === true, "init-result CodeGraph required 应为 true");
1246
- addCheck("init-result CodeGraph command", initResult.codeGraph && initResult.codeGraph.command === "codegraph init -i", "init-result CodeGraph command 不一致");
1247
- addCheck("init-result taskTree role count", initResult.taskTree && initResult.taskTree.roleTaskCount === 5, "init-result taskTree.roleTaskCount 应为 5");
1248
-
1249
- requireIncludes("init/xinyun-ai-init/README.md", [
1250
- "当前规则版本:`1.9.0`",
1251
- "项目初始化:<项目显示名>",
1252
- "xinyun-ai/tasks/task-index.json",
1253
- "xinyun-ai/tasks/.archive-transactions/<archiveTransactionId>.json",
1254
- "taskKind=initialization-record",
1255
- "taskKind=role-execution",
1256
- "status=idle",
1257
- "taskId=null",
1258
- "title=暂无待执行任务",
1259
- "codeGraphRecordId",
1260
- "codegraph init -i",
1261
- "permission-denied",
1262
- "MCP 未连接或健康状态无法确认=`unknown`",
1263
- ]);
1264
-
1265
- requireIncludes("init/xinyun-ai-init/templates/core-rules.template.md", [
1266
- "v1.7.1 初始化主任务、角色子任务与归档",
1267
- "v1.7.1 CodeGraph 必备初始化与状态闭环",
1268
- "项目初始化:<项目显示名>",
1269
- "xinyun-ai/tasks/<taskId>/subtasks/<roleTaskId>.md",
1270
- "executionEligible=true",
1271
- "xinyun-ai/tasks/archive/<taskId>/",
1272
- "prepared",
1273
- "recovery-required",
1274
- "codeGraphRecordId",
1275
- "degradationAuthorized=true",
1276
- ]);
1277
-
1278
- requireIncludes("init/xinyun-ai-init/templates/AGENTS.template.md", [
1279
- "v1.7.1 初始化任务树与 CodeGraph",
1280
- "项目初始化:<项目显示名>",
1281
- "xinyun-ai/tasks/task-index.json",
1282
- "xinyun-ai/tasks/.archive-transactions/<archiveTransactionId>.json",
1283
- "codeGraphRecordId",
1284
- "codegraph init -i",
1285
- ]);
1286
-
1287
- requireIncludes("init/xinyun-ai-init/templates/current-task.template.md", [
1288
- "初始化任务树",
1289
- "任务归档",
1290
- "CodeGraph 必备初始化",
1291
- "currentTaskIdleStatus:status=idle, taskId=null, title=暂无待执行任务",
1292
- "codeGraphRecordId",
1293
- ]);
1294
-
1295
- requireIncludes("init/xinyun-ai-init/rules/init-rules.md", [
1296
- "v1.7.1 初始化任务树与 CodeGraph",
1297
- "xinyun-ai/tasks/task-index.json",
1298
- "codegraph init -i",
1299
- ]);
1300
- requireIncludes("init/xinyun-ai-init/rules/upgrade-rules.md", ["v1.7.1 升级补齐", "CodeGraph 状态闭环"]);
1301
- requireIncludes("init/xinyun-ai-init/rules/directory-self-completion.md", ["v1.7.1 任务树、归档与 CodeGraph 目录"]);
1302
- requireIncludes("init/xinyun-ai-init/rules/session-workbench.md", ["v1.7.1 任务单补充字段"]);
1303
- }
1304
-
1305
- function verifyJsonAndMarkdown() {
1306
- const jsonFiles = walkFiles(initRoot).filter((filePath) => filePath.endsWith(".json"));
1307
- const mdFiles = walkFiles(initRoot).filter((filePath) => filePath.endsWith(".md"));
1308
-
1309
- for (const filePath of jsonFiles) {
1310
- requireJson(rel(filePath));
1311
- }
1312
-
1313
- for (const filePath of mdFiles) {
1314
- requireMarkdownBalanced(rel(filePath));
1315
- }
1316
- }
1317
-
1318
- function verifyV172Contracts() {
1319
- const manifestTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
1320
- const projectIndexTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
1321
- const taskIndex = JSON.parse(readText("init/xinyun-ai-init/templates/task-index.template.json"));
1322
- const roleExecution = readText("init/xinyun-ai-init/templates/role-execution.template.md");
1323
- const expectedPriority = {
1324
- "project-owner": 10,
1325
- "project-product": 20,
1326
- "chief-engineer": 30,
1327
- "programmer": 40,
1328
- "test-reviewer": 50,
1329
- };
1330
-
1331
- requireFile("init/xinyun-ai-init/templates/role-execution.template.md");
1332
- requireFile("test-scenarios/v1.7.2-scenarios.md");
1333
- addCheck(
1334
- "manifest v1.7.2 roleExecutionVisibility",
1335
- manifestTemplate.capabilities && manifestTemplate.capabilities.roleExecutionVisibility === true,
1336
- "manifest 缺少 roleExecutionVisibility 能力"
1337
- );
1338
- addCheck(
1339
- "manifest roleExecutionDirectory",
1340
- manifestTemplate.tasking && manifestTemplate.tasking.roleExecutionDirectory === "xinyun-ai/tasks/role-execution/",
1341
- "manifest roleExecutionDirectory 不一致"
1342
- );
1343
- addCheck(
1344
- "project-index roleExecutionDirectory",
1345
- projectIndexTemplate.tasking && projectIndexTemplate.tasking.roleExecutionDirectory === "xinyun-ai/tasks/role-execution/",
1346
- "project-index roleExecutionDirectory 不一致"
1347
- );
1348
- addCheck(
1349
- "manifest roleExecution path pattern",
1350
- manifestTemplate.taskTree && manifestTemplate.taskTree.roleExecutionPathPattern === "xinyun-ai/tasks/role-execution/<roleTaskId>.md",
1351
- "manifest roleExecution path pattern 不一致"
1352
- );
1353
- addCheck(
1354
- "task-index roleExecutionDirectory",
1355
- taskIndex.roleExecutionDirectory === "xinyun-ai/tasks/role-execution/",
1356
- "task-index roleExecutionDirectory 不一致"
1357
- );
1358
- addCheck("task-index roleExecutionTaskIds array", Array.isArray(taskIndex.roleExecutionTaskIds), "roleExecutionTaskIds 必须是数组");
1359
- addCheck(
1360
- "task-index roleExecution status enum",
1361
- JSON.stringify(taskIndex.roleExecutionStatusEnum) === JSON.stringify(["pending", "assigned", "accepted", "executing", "paused", "blocked", "completed", "cancelled"]),
1362
- "roleExecutionStatusEnum 不完整"
1363
- );
1364
- addCheck(
1365
- "task-index task sort order",
1366
- JSON.stringify(taskIndex.taskSortOrder) === JSON.stringify(["priority", "createdAt", "roleId", "taskId"]),
1367
- "任务稳定排序字段不一致"
1368
- );
1369
- addCheck(
1370
- "task-index current task idle policy",
1371
- taskIndex.currentTaskPolicy && taskIndex.currentTaskPolicy.idleWhenActiveTaskIdsEmpty === true && taskIndex.currentTaskPolicy.idleTaskId === null,
1372
- "current-task idle policy 不完整"
1373
- );
1374
- addCheck(
1375
- "task-index role idempotency fields",
1376
- taskIndex.idempotency && JSON.stringify(taskIndex.idempotency.keyFields) === JSON.stringify(["sourceTaskId", "roleId", "taskKind", "targetVersion"]) && taskIndex.idempotency.algorithm === "JCS-SHA-256" && taskIndex.idempotency.duplicatePolicy === "reuse",
1377
- "逐角色幂等契约不完整"
1378
- );
1379
- for (const [roleId, priority] of Object.entries(expectedPriority)) {
1380
- addCheck(
1381
- `task-index priority ${roleId}`,
1382
- taskIndex.roleExecutionPriority && taskIndex.roleExecutionPriority[roleId] === priority,
1383
- `${roleId} 默认优先级不一致`
1384
- );
1385
- addCheck(
1386
- `manifest priority ${roleId}`,
1387
- manifestTemplate.taskTree && manifestTemplate.taskTree.roleExecutionPriority && manifestTemplate.taskTree.roleExecutionPriority[roleId] === priority,
1388
- `${roleId} manifest 默认优先级不一致`
1389
- );
1390
- }
1391
-
1392
- const requiredRoleFields = [
1393
- "taskId", "roleTaskId", "parentTaskId", "roleId", "taskKind", "title", "priority", "status",
1394
- "assignmentStatus", "understandingStatus", "confirmationStatus", "memberId", "sessionId",
1395
- "executionEligible", "blockedReason", "nextAction", "sourceTaskId", "idempotencyKey", "createdAt", "updatedAt",
1396
- ];
1397
- for (const field of requiredRoleFields) {
1398
- addCheck(`role-execution template field ${field}`, roleExecution.includes(`- ${field}:`), `role-execution 模板缺少 ${field}`);
1399
- }
1400
- requireIncludes("init/xinyun-ai-init/README.md", [
1401
- "当前规则版本:`1.9.0`",
1402
- "xinyun-ai/tasks/role-execution/<roleTaskId>.md",
1403
- "activeTaskIds",
1404
- "executableTaskIds",
1405
- "priority ASC",
1406
- "JCS-SHA-256",
1407
- "blockedReason=write-failed",
1408
- ]);
1409
- requireIncludes("init/xinyun-ai-init/templates/core-rules.template.md", [
1410
- "v1.7.2 初始化后角色任务可见性与执行任务分离",
1411
- "xinyun-ai/tasks/role-execution/<roleTaskId>.md",
1412
- "activeTaskIds",
1413
- "executableTaskIds",
1414
- "JCS-SHA-256",
1415
- ]);
1416
- requireIncludes("init/xinyun-ai-init/rules/init-rules.md", ["v1.7.2 角色后续任务可见性", "role-execution"]);
1417
- requireIncludes("init/xinyun-ai-init/rules/upgrade-rules.md", ["v1.7.2 升级补建角色后续任务", "write-failed"]);
1418
- requireIncludes("init/xinyun-ai-init/rules/directory-self-completion.md", ["v1.7.2 任务可见性目录", "role-execution"]);
1419
- requireIncludes("init/xinyun-ai-init/rules/session-workbench.md", ["v1.7.2 角色执行任务补充字段", "roleExecutionResult"]);
1420
- }
1421
-
1422
- function verifyV173Contracts() {
1423
- const manifestTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
1424
- const projectIndexTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
1425
- const taskIndex = JSON.parse(readText("init/xinyun-ai-init/templates/task-index.template.json"));
1426
- const initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
1427
- const assignments = JSON.parse(readText("init/xinyun-ai-init/templates/team/assignments.json"));
1428
- const bindingTemplate = JSON.parse(readText("init/xinyun-ai-init/templates/role-session-binding.template.json"));
1429
- const roleExecution = readText("init/xinyun-ai-init/templates/role-execution.template.md");
1430
- const statusEnum = ["pending", "creating", "created", "onboarding", "ready", "blocked", "failed", "closed"];
1431
-
1432
- requireFile("init/xinyun-ai-init/templates/role-session-binding.template.json");
1433
- requireFile("test-scenarios/v1.7.3-scenarios.md");
1434
-
1435
- addCheck(
1436
- "manifest v1.7.3 codexRoleSessionOrchestration",
1437
- manifestTemplate.capabilities && manifestTemplate.capabilities.codexRoleSessionOrchestration === true,
1438
- "manifest 缺少 codexRoleSessionOrchestration 能力"
1439
- );
1440
- addCheck(
1441
- "manifest roleSessions provider codex",
1442
- manifestTemplate.roleSessions && manifestTemplate.roleSessions.provider === "codex",
1443
- "manifest roleSessions.provider 必须为 codex"
1444
- );
1445
- addCheck(
1446
- "manifest roleSessions targetVersion=current",
1447
- manifestTemplate.roleSessions && manifestTemplate.roleSessions.targetVersion === CURRENT_VERSION,
1448
- "manifest roleSessions.targetVersion 必须为当前版本"
1449
- );
1450
- addCheck(
1451
- "manifest roleSessions bindings path",
1452
- manifestTemplate.roleSessions && manifestTemplate.roleSessions.bindings === "xinyun-ai/sessions/role-session-bindings.json",
1453
- "manifest roleSessions.bindings 不一致"
1454
- );
1455
- addCheck(
1456
- "manifest roleSessions directory",
1457
- manifestTemplate.roleSessions && manifestTemplate.roleSessions.directory === "xinyun-ai/sessions/roles/",
1458
- "manifest roleSessions.directory 不一致"
1459
- );
1460
- addCheck(
1461
- "manifest roleSessions bindingTemplate",
1462
- manifestTemplate.roleSessions && manifestTemplate.roleSessions.bindingTemplate === "xinyun-ai-init/templates/role-session-binding.template.json",
1463
- "manifest roleSessions.bindingTemplate 不一致"
1464
- );
1465
- addCheck(
1466
- "manifest roleSessions requiredRoleCount=5",
1467
- manifestTemplate.roleSessions && manifestTemplate.roleSessions.requiredRoleCount === 5,
1468
- "manifest roleSessions.requiredRoleCount 必须为 5"
1469
- );
1470
- addCheck(
1471
- "manifest roleSessions status enum",
1472
- manifestTemplate.roleSessions && JSON.stringify(manifestTemplate.roleSessions.statusEnum) === JSON.stringify(statusEnum),
1473
- "manifest roleSessions.statusEnum 不完整"
1474
- );
1475
- addCheck(
1476
- "manifest roleSessions idempotency fields",
1477
- manifestTemplate.roleSessions && manifestTemplate.roleSessions.idempotency && JSON.stringify(manifestTemplate.roleSessions.idempotency.keyFields) === JSON.stringify(["projectRootHash", "workspaceScope", "repositoryScopeHash", "workstream", "taskId", "roleId", "provider", "targetVersion"]) && manifestTemplate.roleSessions.idempotency.algorithm === "RFC8785-JCS-SHA-256",
1478
- "manifest roleSessions.idempotency.keyFields 不一致"
1479
- );
1480
- addCheck(
1481
- "manifest roleSessions legacy creation index",
1482
- manifestTemplate.roleSessions && manifestTemplate.roleSessions.idempotency && JSON.stringify(manifestTemplate.roleSessions.idempotency.legacyCreationIndexFields) === JSON.stringify(["taskId", "roleId", "provider", "targetVersion"]) && manifestTemplate.roleSessions.idempotency.legacyCreationIndexPolicy.includes("never used for candidate selection"),
1483
- "manifest roleSessions 旧兼容索引策略不完整"
1484
- );
1485
- addCheck(
1486
- "manifest roleSessions host unsupported policy",
1487
- manifestTemplate.roleSessions && manifestTemplate.roleSessions.hostUnsupportedPolicy === "local-degraded-no-fake-session-id",
1488
- "manifest roleSessions.hostUnsupportedPolicy 不一致"
1489
- );
1490
-
1491
- addCheck(
1492
- "project-index roleSessions path",
1493
- projectIndexTemplate.roleSessions && projectIndexTemplate.roleSessions.bindings === "xinyun-ai/sessions/role-session-bindings.json",
1494
- "project-index roleSessions.bindings 不一致"
1495
- );
1496
- addCheck(
1497
- "project-index roleSessions status enum",
1498
- projectIndexTemplate.roleSessions && JSON.stringify(projectIndexTemplate.roleSessions.statusEnum) === JSON.stringify(statusEnum),
1499
- "project-index roleSessions.statusEnum 不完整"
1500
- );
1501
- addCheck("project-index roleSessions records array", projectIndexTemplate.roleSessions && Array.isArray(projectIndexTemplate.roleSessions.records), "project-index roleSessions.records 必须是数组");
1502
- addCheck(
1503
- "project-index roleSessions idempotency fields",
1504
- projectIndexTemplate.roleSessions && projectIndexTemplate.roleSessions.idempotency && JSON.stringify(projectIndexTemplate.roleSessions.idempotency.keyFields) === JSON.stringify(["projectRootHash", "workspaceScope", "repositoryScopeHash", "workstream", "taskId", "roleId", "provider", "targetVersion"]) && projectIndexTemplate.roleSessions.idempotency.algorithm === "RFC8785-JCS-SHA-256",
1505
- "project-index roleSessions.idempotency 不一致"
1506
- );
1507
-
1508
- addCheck("task-index roleSessionBindingIds array", Array.isArray(taskIndex.roleSessionBindingIds), "task-index roleSessionBindingIds 必须是数组");
1509
- addCheck("task-index roleSessionBindings array", Array.isArray(taskIndex.roleSessionBindings), "task-index roleSessionBindings 必须是数组");
1510
- addCheck(
1511
- "task-index roleSession status enum",
1512
- JSON.stringify(taskIndex.roleSessionStatusEnum) === JSON.stringify(statusEnum),
1513
- "task-index roleSessionStatusEnum 不完整"
1514
- );
1515
- addCheck(
1516
- "task-index roleSession idempotency fields",
1517
- taskIndex.roleSessionIdempotency && JSON.stringify(taskIndex.roleSessionIdempotency.keyFields) === JSON.stringify(["projectRootHash", "workspaceScope", "repositoryScopeHash", "workstream", "taskId", "roleId", "provider", "targetVersion"]) && taskIndex.roleSessionIdempotency.algorithm === "RFC8785-JCS-SHA-256",
1518
- "task-index roleSessionIdempotency.keyFields 不一致"
1519
- );
1520
- addCheck(
1521
- "task-index legacy creation index",
1522
- taskIndex.roleSessionIdempotency && JSON.stringify(taskIndex.roleSessionIdempotency.legacyCreationIndexFields) === JSON.stringify(["taskId", "roleId", "provider", "targetVersion"]) && taskIndex.roleSessionIdempotency.legacyCreationIndexPolicy.includes("never used for candidate selection"),
1523
- "task-index 旧兼容索引策略不完整"
1524
- );
1525
-
1526
- addCheck("init-result roleSessions provider codex", initResult.roleSessions && initResult.roleSessions.provider === "codex", "init-result roleSessions.provider 必须为 codex");
1527
- addCheck("init-result roleSessions requiredRoleCount=5", initResult.roleSessions && initResult.roleSessions.requiredRoleCount === 5, "init-result roleSessions.requiredRoleCount 必须为 5");
1528
- for (const field of ["createdCount", "reusedCount", "failedCount", "blockedCount", "localDegradedCount"]) {
1529
- addCheck(`init-result roleSessions ${field}`, initResult.roleSessions && typeof initResult.roleSessions[field] === "number", `init-result roleSessions.${field} 必须是数字`);
1530
- }
1531
-
1532
- for (const field of ["sessionId", "parentSessionId", "provider", "sessionStatus"]) {
1533
- addCheck(`assignments required field ${field}`, assignments.recordContract && assignments.recordContract.requiredFields.includes(field), `assignments recordContract 缺少 ${field}`);
1534
- }
1535
- addCheck("assignments session binding rule mentions real host value", assignments.recordContract && assignments.recordContract.sessionBindingRule.includes("real host-returned value"), "assignments sessionBindingRule 必须说明真实宿主返回值");
1536
-
1537
- addCheck("binding template provider codex", bindingTemplate.provider === "codex", "binding template provider 必须为 codex");
1538
- addCheck("binding template targetVersion=current", bindingTemplate.targetVersion === CURRENT_VERSION, "binding template targetVersion 必须为当前版本");
1539
- addCheck("binding template fakeSessionId prohibited", bindingTemplate.degradation && bindingTemplate.degradation.fakeSessionIdProhibited === true, "binding template 必须禁止伪造 sessionId");
1540
- addCheck("binding template onboarding readOnly", bindingTemplate.onboarding && bindingTemplate.onboarding.readOnly === true, "binding template onboarding.readOnly 必须为 true");
1541
-
1542
- for (const field of ["parentSessionId", "provider", "sessionStatus", "sessionBindingId", "sessionBindingPath", "sessionIdempotencyKey"]) {
1543
- addCheck(`role-execution v1.7.3 field ${field}`, roleExecution.includes(`- ${field}:`), `role-execution 模板缺少 ${field}`);
1544
- }
1545
-
1546
- const snippets = [
1547
- "v1.7.3 Codex 角色会话自动创建与绑定",
1548
- "provider=codex",
1549
- "sessionStatus=pending/creating/created/onboarding/ready/blocked/failed/closed",
1550
- "projectRootHash, workspaceScope, repositoryScopeHash, workstream, taskId, roleId, provider, targetVersion",
1551
- "RFC8785-JCS-SHA-256",
1552
- "真实 `sessionId`",
1553
- "不得伪造 sessionId",
1554
- "local-degraded-no-fake-session-id",
1555
- "onboarding",
1556
- "created-but-writeback-failed",
1557
- "创建成功不等于业务代码修改授权",
1558
- ];
1559
- requireIncludes("init/xinyun-ai-init/README.md", snippets);
1560
- requireIncludes("init/xinyun-ai-init/templates/core-rules.template.md", snippets);
1561
- requireIncludes("init/xinyun-ai-init/templates/AGENTS.template.md", ["v1.7.3 Codex 角色会话自动创建与绑定", "provider=codex", "local-degraded-no-fake-session-id"]);
1562
- requireIncludes("init/xinyun-ai-init/rules/init-rules.md", ["v1.7.3 Codex 角色会话初始化", "provider=codex", "local-degraded-no-fake-session-id"]);
1563
- requireIncludes("init/xinyun-ai-init/rules/upgrade-rules.md", ["v1.7.3 升级创建和绑定真实角色会话", "created-but-writeback-failed", "不得伪造 sessionId"]);
1564
- requireIncludes("init/xinyun-ai-init/rules/directory-self-completion.md", ["v1.7.3 角色会话绑定目录", "xinyun-ai/sessions/role-session-bindings.json", "local-degraded-no-fake-session-id"]);
1565
- requireIncludes("init/xinyun-ai-init/rules/session-workbench.md", ["v1.7.3 角色会话交接字段", "roleSessionIdempotency", "不得伪造 sessionId"]);
1566
- requireIncludes("init/xinyun-ai-init/templates/project-guide.template.md", ["v1.7.3 Codex role session anchors", "roleSessionIdempotency", "local-degraded-no-fake-session-id"]);
1567
- requireIncludes("init/xinyun-ai-init/templates/project-check.template.md", ["v1.7.3 checks", "provider=codex", "不存在伪造 sessionId"]);
1568
- requireIncludes("test-scenarios/scenarios.md", ["当前必测场景为 1-133", "当前观察场景为 106 和 119", "## 89. v1.7.3 Codex 真实角色会话创建", "## 96. v1.7.3 普通咨询边界", "## 97. Skill"]);
1569
- requireIncludes("test-scenarios/review-template.md", ["1-133 必测", "89. v1.7.3 Codex 真实角色会话创建", "96. v1.7.3 普通咨询边界", "97. Skill"]);
1570
- }
1571
-
1572
- function verifyV18Contracts() {
1573
- const manifest = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
1574
- const projectIndex = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
1575
- const skillAssignments = JSON.parse(readText("init/xinyun-ai-init/templates/skills-assignments.template.json"));
1576
- const skillRegistry = JSON.parse(readText("init/xinyun-ai-init/templates/skills-registry.template.json"));
1577
- const frontendAudit = JSON.parse(readText("init/xinyun-ai-init/templates/frontend-audit.template.json"));
1578
- const temporarySession = JSON.parse(readText("init/xinyun-ai-init/templates/temporary-session.template.json"));
1579
- const transaction = JSON.parse(readText("init/xinyun-ai-init/templates/coordination-transaction.template.json"));
1580
- const requiredFiles = [
1581
- "init/xinyun-ai-init/rules/coordination.md",
1582
- "init/xinyun-ai-init/rules/skills.md",
1583
- "init/xinyun-ai-init/rules/frontend-audit.md",
1584
- "init/xinyun-ai-init/rules/temporary-sessions.md",
1585
- "init/xinyun-ai-init/templates/coordination-project-facts.template.json",
1586
- "init/xinyun-ai-init/templates/coordination-change-ledger.template.json",
1587
- "init/xinyun-ai-init/templates/coordination-contract-snapshot.template.json",
1588
- "init/xinyun-ai-init/templates/coordination-conflict-record.template.json",
1589
- "init/xinyun-ai-init/templates/coordination-transaction.template.json",
1590
- "init/xinyun-ai-init/templates/skills-registry.template.json",
1591
- "init/xinyun-ai-init/templates/skills-assignments.template.json",
1592
- "init/xinyun-ai-init/templates/frontend-audit.template.json",
1593
- "init/xinyun-ai-init/templates/temporary-session.template.json",
1594
- "test-scenarios/v1.8.0-scenarios.md",
1595
- ];
1596
- for (const file of requiredFiles) requireFile(file);
1597
-
1598
- for (const capability of ["sharedProjectFactsCoordination", "skillRouting", "frontendCouplingAudit", "temporaryProgrammerSessions"]) {
1599
- addCheck(`manifest capability ${capability}`, manifest.capabilities && manifest.capabilities[capability] === true, `manifest.capabilities.${capability} 必须为 true`);
1600
- }
1601
- const pathChecks = [
1602
- [manifest.coordination, "directory", "xinyun-ai/coordination/"],
1603
- [manifest.skills, "directory", "xinyun-ai/skills/"],
1604
- [manifest.frontendAudit, "directory", "xinyun-ai/frontend-audits/"],
1605
- [manifest.temporarySessions, "directory", "xinyun-ai/sessions/temporary/"],
1606
- [projectIndex.coordination, "directory", "xinyun-ai/coordination/"],
1607
- [projectIndex.skills, "directory", "xinyun-ai/skills/"],
1608
- [projectIndex.frontendAudit, "directory", "xinyun-ai/frontend-audits/"],
1609
- [projectIndex.temporarySessions, "directory", "xinyun-ai/sessions/temporary/"],
1610
- ];
1611
- for (const [object, field, expected] of pathChecks) addCheck(`v1.8 path ${expected}`, object && object[field] === expected, `路径必须为 ${expected}`);
1612
-
1613
- addCheck("coordination transaction phase enum", JSON.stringify(transaction.phaseEnum) === JSON.stringify(["prepared", "validated", "renamed", "revision-updated", "committed", "recovery-required", "blocked"]), "事务阶段不完整");
1614
- addCheck("Skill uses assignmentStatus", skillAssignments.recordContract && skillAssignments.recordContract.requiredFields.includes("assignmentStatus"), "Skill 分配必须使用 assignmentStatus");
1615
- addCheck("Skill does not use status alias", !JSON.stringify(skillAssignments).includes("assignments.json.status"), "不得使用 assignments.json.status");
1616
- addCheck("Skill usageStatus mapping exists", skillAssignments.recordContract && skillAssignments.recordContract.statusMapping && skillAssignments.recordContract.statusMapping.blocked.includes("failed"), "缺少失败到 blocked 的映射");
1617
- addCheck("Skill failed requires reason/action", skillAssignments.recordContract && skillAssignments.recordContract.failedRule.includes("failureReason") && skillAssignments.recordContract.failedRule.includes("nextAction"), "缺少失败证据契约");
1618
- addCheck("Skill registry separates availability/trust", skillRegistry.recordContract && skillRegistry.recordContract.requiredFields.includes("availabilityStatus") && skillRegistry.recordContract.requiredFields.includes("trustStatus"), "Skill 可用性和可信度必须独立");
1619
- addCheck("frontend audit-only decision", frontendAudit.decision === "audit-only", "默认必须为 audit-only");
1620
- addCheck("frontend audit status enum", frontendAudit.statusEnum && frontendAudit.statusEnum.includes("unknown"), "审计状态枚举不完整");
1621
- addCheck("frontend refactor evidence contract", frontendAudit.refactorNowRequired && frontendAudit.refactorNowRequired.includes("userConfirmationId") && frontendAudit.refactorNowRequired.includes("diffEvidence"), "refactor-now 证据契约不完整");
1622
- addCheck("temporary session maxConcurrent=3", temporarySession.maxConcurrent === 3, "临时会话并发上限必须为 3");
1623
- addCheck("temporary session has occupancyStatus", temporarySession.occupancyStatusEnum && temporarySession.occupancyStatusEnum.includes("unknown"), "缺少 occupancyStatus=unknown");
1624
-
1625
- const v18Snippets = ["v1.8", "factStatus", "changeStatus", "conflictStatus", "assignmentStatus", "usageStatus", "audit-only", "refactor-now", "occupancyStatus=unknown", "coordinationTransactionId"];
1626
- requireIncludes("init/xinyun-ai-init/README.md", v18Snippets);
1627
- requireIncludes("init/xinyun-ai-init/templates/core-rules.template.md", v18Snippets);
1628
- requireIncludes("init/xinyun-ai-init/rules/coordination.md", ["三道门禁", "coordinationTransactionId", "status-inconsistent"]);
1629
- requireIncludes("init/xinyun-ai-init/rules/skills.md", ["assignmentStatus", "usageStatus", "failureReason", "nextAction"]);
1630
- requireIncludes("init/xinyun-ai-init/rules/frontend-audit.md", ["audit-only", "refactor-now", "unverifiedScope"]);
1631
- requireIncludes("init/xinyun-ai-init/rules/temporary-sessions.md", ["最多同时占用 3 个运行额度", "occupancyStatus=unknown", "releaseAudit"]);
1632
- requireIncludes("test-scenarios/scenarios.md", ["当前必测场景为 1-133", "当前观察场景为 106 和 119", "## 98. v1.8-A", "## 105. v1.8 敏感信息边界"]);
1633
- requireIncludes("test-scenarios/review-template.md", ["1-133 必测", "98. v1.8-A 状态域和来源一致性", "105. v1.8 敏感信息边界"]);
1634
- }
1635
-
1636
- function verifyV19Contracts() {
1637
- const manifest = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
1638
- const projectIndex = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
1639
- const identity = JSON.parse(readText("init/xinyun-ai-init/templates/project-identity.template.json"));
1640
- const candidates = JSON.parse(readText("init/xinyun-ai-init/templates/session-candidates.template.json"));
1641
- const landscape = JSON.parse(readText("init/xinyun-ai-init/templates/technical-landscape.template.json"));
1642
- const requirementPacket = JSON.parse(readText("init/xinyun-ai-init/templates/requirement-packet.template.json"));
1643
- const impactPacket = JSON.parse(readText("init/xinyun-ai-init/templates/technical-impact-packet.template.json"));
1644
- const database = JSON.parse(readText("init/xinyun-ai-init/templates/database-authorization.template.json"));
1645
- const requiredFiles = [
1646
- "init/xinyun-ai-init/templates/project-identity.template.json",
1647
- "init/xinyun-ai-init/templates/session-candidates.template.json",
1648
- "init/xinyun-ai-init/templates/technical-landscape.template.json",
1649
- "init/xinyun-ai-init/templates/requirement-packet.template.json",
1650
- "init/xinyun-ai-init/templates/technical-impact-packet.template.json",
1651
- "init/xinyun-ai-init/templates/database-authorization.template.json",
1652
- "test-scenarios/v1.9.0-scenarios.md",
1653
- ];
1654
-
1655
- for (const file of requiredFiles) requireFile(file);
1656
-
1657
- for (const capability of ["projectSessionIsolation", "roleDisplayNaming", "technicalLandscapeCoordination", "databaseSqlOnlyAuthorization"]) {
1658
- addCheck(`manifest v1.9 capability ${capability}`, manifest.capabilities && manifest.capabilities[capability] === true, `缺少 ${capability}`);
1659
- }
1660
-
1661
- const expectedPaths = {
1662
- projectIdentity: "xinyun-ai/project-identity.json",
1663
- sessionCandidates: "xinyun-ai/sessions/session-candidates.json",
1664
- technicalLandscape: "xinyun-ai/technical-landscape.json",
1665
- requirementPacket: "xinyun-ai/packets/requirement-packet.json",
1666
- technicalImpactPacket: "xinyun-ai/packets/technical-impact-packet.json",
1667
- databaseAuthorization: "xinyun-ai/database/authorization.json",
1668
- };
1669
- for (const [key, value] of Object.entries(expectedPaths)) {
1670
- addCheck(`manifest v1.9 path ${key}`, manifest.v19 && manifest.v19[key] === value, `manifest.v19.${key} 应为 ${value}`);
1671
- addCheck(`project-index v1.9 path ${key}`, projectIndex.v19 && projectIndex.v19[key] === value, `project-index.v19.${key} 应为 ${value}`);
1672
- }
1673
-
1674
- addCheck("project identity normalization", identity.normalization && identity.normalization.resolutionMode === "unknown" && identity.normalization.unicodeNormalization === "NFC", "项目身份规范化契约不完整");
1675
- addCheck("project identity hash fields", Object.prototype.hasOwnProperty.call(identity, "projectRootHash") && Object.prototype.hasOwnProperty.call(identity, "repositoryScopeHash"), "项目身份缺少 hash 字段");
1676
- addCheck("session match enum excludes current-match", !candidates.sessionMatchStatusEnum.includes("current-match") && candidates.sessionMatchStatusEnum.includes("reusable") && candidates.sessionMatchStatusEnum.includes("renamed"), "sessionMatchStatus 枚举不符合 v1.9");
1677
- addCheck("session candidate required fields", ["hostRecoveryAvailable", "hostRecoveryEvidence", "selectionEvidence"].every((field) => candidates.candidateRequiredFields.includes(field) || Object.prototype.hasOwnProperty.call(candidates, field)), "会话候选恢复/选择证据字段不完整");
1678
- addCheck("session reuse algorithm", candidates.reuseIdempotency && candidates.reuseIdempotency.algorithm === "RFC8785-JCS-SHA-256", "会话复用算法不完整");
1679
- addCheck("technical landscape ready gate", landscape.coverage.coverageStatus === "unknown" && landscape.status === "not-started", "技术全景初始状态不安全");
1680
- addCheck("technical landscape status contract", landscape.status === "not-started" && landscape.coverage.coverageStatus === "unknown" && Array.isArray(landscape.unverifiedScope), "技术全景状态契约不完整");
1681
- addCheck("packet minimum fields", [requirementPacket, impactPacket].every((packet) => ["schemaVersion", "packetId", "requirementId", "taskId", "projectRootHash", "version", "status", "content", "evidence", "sourceRevision", "contentHash", "createdAt", "updatedAt"].every((field) => Object.prototype.hasOwnProperty.call(packet, field))), "packet 最小字段不完整");
1682
- addCheck("packet hash algorithm", manifest.v19 && manifest.v19.packetHashAlgorithm === "RFC8785-JCS-SHA-256", "packet hash 算法不完整");
1683
- addCheck("database legacy sql-only compatibility", database.legacyDatabaseAccessMode === "sql-only" && database.databaseAccessMode === "local-files-read-only" && database.sqlExecutionMode === "generate-only", "database legacy compatibility marker is incomplete");
1684
- addCheck("database authorization separation", ["connectionStatus", "queryAuthorization", "schemaChangeAuthorization", "dataMutationAuthorization"].every((field) => Object.prototype.hasOwnProperty.call(database, field)), "数据库权限未分离");
1685
- addCheck("database local-files-read-only default", database.databaseAccessMode === "local-files-read-only" && database.legacyDatabaseAccessMode === "sql-only" && database.sqlExecutionMode === "generate-only" && database.executionStatus === "needs-confirmation" && database.connectionStatus === "not-requested" && database.connected === false && database.sqlExecuted === false, "database local-file read-only default is incomplete");
1686
- const localDatabaseScope = ["*.sql", "*.ddl", "*.schema", "*.migration", "database/", "migrations/", "schema/", "models/"];
1687
- addCheck("database local file policy", JSON.stringify(database.localDatabaseFileScope) === JSON.stringify(localDatabaseScope) && database.localFileReadPolicy === "database-related-task-only" && database.forbiddenOperations.includes("database-connection") && database.forbiddenOperations.includes("sql-execution"), "database local file scope or forbidden operations are incomplete");
1688
- addCheck("database defaults across v19 templates", manifest.v19 && projectIndex.v19 && manifest.v19.databaseAccessModeDefault === "local-files-read-only" && projectIndex.v19.databaseAccessModeDefault === manifest.v19.databaseAccessModeDefault && manifest.v19.legacyDatabaseAccessMode === "sql-only" && projectIndex.v19.legacyDatabaseAccessMode === "sql-only" && manifest.v19.sqlExecutionMode === "generate-only" && projectIndex.v19.sqlExecutionMode === "generate-only", "manifest and project-index database policy is inconsistent");
1689
- const authorizationStates = ["not-requested", "requested", "authorized", "denied", "expired", "failed", "unknown"];
1690
- addCheck("database authorization state enum", database.authorizationStatusEnum && JSON.stringify(database.authorizationStatusEnum) === JSON.stringify(authorizationStates) && ["connectionStatusEnum", "queryAuthorizationEnum", "schemaChangeAuthorizationEnum", "dataMutationAuthorizationEnum"].every((field) => JSON.stringify(database[field]) === JSON.stringify(authorizationStates)), "数据库四类授权状态枚举不完整");
1691
- addCheck("database authorization transitions", database.authorizationTransitionRules && database.authorizationTransitionRules.authorized.includes("expired") && database.invalidatingChanges.includes("statement-hash-changed") && database.invalidatingAction.includes("needs-confirmation"), "数据库授权失效转移不完整");
1692
- addCheck("database redaction status enum", JSON.stringify(database.redactionStatusEnum) === JSON.stringify(["verified", "unverified", "failed"]) && database.redactionStatus === "verified", "数据库脱敏状态枚举不完整");
1693
- addCheck("database execution status enum", JSON.stringify(database.executionStatusEnum) === JSON.stringify(["not-run", "needs-confirmation", "authorized", "executed", "failed", "unknown"]), "数据库执行状态枚举不完整");
1694
- addCheck("database statement hash contract", database.statementHashAlgorithm === "RFC8785-JCS-SHA-256" && database.statementHashCanonicalInput.includes("parameters") && database.statementHashCanonicalInput.includes("targetEnvironment"), "statementHash 契约不完整");
1695
- addCheck("database audit contract", database.auditRequiredFields.includes("auditId") && database.auditRequiredFields.includes("statementHash") && database.auditRequiredFields.includes("redactionStatus"), "数据库 audit 契约不完整");
1696
-
1697
- const snippets = [
1698
- "v1.9",
1699
- "lexical-fallback",
1700
- "sessionMatchStatus",
1701
- "duplicate-not-primary",
1702
- "selectionEvidence",
1703
- "项目简称|角色中文名|职责名称",
1704
- "technical-landscape",
1705
- "coverageStatus=full",
1706
- "packet-stale",
1707
- "RFC 8785 JCS-SHA-256",
1708
- "databaseAccessMode=local-files-read-only",
1709
- "legacyDatabaseAccessMode=sql-only",
1710
- "statementHash",
1711
- "targetEnvironment",
1712
- ];
1713
- for (const file of [
1714
- "init/xinyun-ai-init/README.md",
1715
- "init/xinyun-ai-init/templates/AGENTS.template.md",
1716
- "init/xinyun-ai-init/templates/core-rules.template.md",
1717
- "init/xinyun-ai-init/rules/init-rules.md",
1718
- "init/xinyun-ai-init/rules/upgrade-rules.md",
1719
- "init/xinyun-ai-init/rules/session-workbench.md",
1720
- ]) requireIncludes(file, snippets);
1721
-
1722
- requireIncludes("test-scenarios/v1.9.0-scenarios.md", ["## 107.", "## 109.", "## 113.", "## 115.", "## 118.", "packet-stale", "sql-only", "行为证据"]);
1723
- verifyV19BehaviorEvidence();
1724
- }
1725
-
1726
- function sha256Text(value) {
1727
- return crypto.createHash("sha256").update(value, "utf8").digest("hex");
1728
- }
1729
-
1730
- function verifyV19BehaviorEvidence() {
1731
- const relativePath = "test-scenarios/v1.9.0-behavior-evidence.json";
1732
- requireFile(relativePath);
1733
- if (!fs.existsSync(path.join(root, relativePath))) return;
1734
- let report;
1735
- try {
1736
- report = JSON.parse(readText(relativePath));
1737
- addCheck("v1.9 behavior evidence JSON parse", true, "行为证据 JSON 可解析");
1738
- } catch (error) {
1739
- addCheck("v1.9 behavior evidence JSON parse", false, error.message);
1740
- return;
1741
- }
1742
- const expectedIds = Array.from({ length: 12 }, (_, index) => 107 + index);
1743
- const scenarios = Array.isArray(report.scenarios) ? report.scenarios : [];
1744
- addCheck("v1.9 behavior evidence source classification", report.evidenceType === "behavioral-replay" && report.executionMode === "controlled-isolated-fixture-replay" && report.realAiSessionVerified === false && typeof report.testMethod === "string" && typeof report.temporaryProjectBoundary === "string", "受控回放证据来源和边界未明确");
1745
- addCheck("v1.9 behavior evidence scenario count", scenarios.length === expectedIds.length, "必须覆盖 107-118");
1746
- addCheck("v1.9 behavior evidence scenario IDs", JSON.stringify(scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(expectedIds), "场景 ID 必须完整且有序");
1747
- const crossProjectScenario = scenarios.find((scenario) => scenario.scenarioId === 109);
1748
- addCheck(
1749
- "v1.9 cross-project reuse negative",
1750
- Boolean(crossProjectScenario && crossProjectScenario.input.includes("projectRootHash") && crossProjectScenario.actualOutput.includes("other-project") && crossProjectScenario.afterSnapshot.includes("createdCount=0")),
1751
- "场景 109 必须证明旧四字段相同但项目身份不同的候选被拒绝且不创建重复绑定"
1752
- );
1753
- const requiredFields = ["scenarioId", "input", "expectedOutput", "actualOutput", "beforeSnapshot", "afterSnapshot", "beforeSnapshotHash", "afterSnapshotHash", "changedFiles", "controlFilesChanged", "forbiddenOperations", "evidence", "sensitiveScan", "result", "recordHash", "recordedAt"];
1754
- for (const scenario of scenarios) {
1755
- const prefix = `v1.9 behavior evidence ${scenario.scenarioId}`;
1756
- addCheck(`${prefix} required fields`, requiredFields.every((field) => Object.prototype.hasOwnProperty.call(scenario, field)), "场景证据字段不完整");
1757
- addCheck(`${prefix} result`, scenario.result === "replay-passed", "受控回放场景必须使用 replay-passed,不得冒充真实行为 passed");
1758
- addCheck(`${prefix} snapshot hashes`, scenario.beforeSnapshotHash === sha256Text(scenario.beforeSnapshot) && scenario.afterSnapshotHash === sha256Text(scenario.afterSnapshot), "before/after 快照 hash 不匹配");
1759
- const recordPayload = { ...scenario };
1760
- delete recordPayload.recordHash;
1761
- addCheck(`${prefix} record hash`, scenario.recordHash === sha256Text(JSON.stringify(recordPayload)), "场景 recordHash 不匹配");
1762
- addCheck(`${prefix} changed files separated`, Array.isArray(scenario.changedFiles) && Array.isArray(scenario.controlFilesChanged), "changedFiles 与 controlFilesChanged 必须分离");
1763
- addCheck(`${prefix} forbidden operations`, scenario.forbiddenOperations && scenario.forbiddenOperations.gitWrite === false && scenario.forbiddenOperations.databaseConnection === false && scenario.forbiddenOperations.sqlExecution === false && scenario.forbiddenOperations.businessCodeWrite === false, "禁止操作证明不完整");
1764
- addCheck(`${prefix} sensitive scan`, scenario.sensitiveScan && scenario.sensitiveScan.status === "pass" && Array.isArray(scenario.sensitiveScan.matches) && scenario.sensitiveScan.matches.length === 0, "敏感信息扫描必须无命中");
1765
- }
1766
- }
1767
-
1768
- function verifyV110Contracts() {
1769
- const requiredFiles = [
1770
- "init/xinyun-ai-init/templates/host-capabilities.template.json",
1771
- "init/xinyun-ai-init/templates/project-status.template.json",
1772
- "init/xinyun-ai-init/templates/preflight-report.template.json",
1773
- "init/xinyun-ai-init/templates/onboarding-report.template.json",
1774
- "init/xinyun-ai-init/templates/takeover-baseline.template.json",
1775
- "init/xinyun-ai-init/templates/control-plane-index.template.json",
1776
- "init/xinyun-ai-init/templates/init-result.template.json",
1777
- "init/xinyun-ai-init/templates/current-task.template.md",
1778
- "test-scenarios/v1.10.0-scenarios.md",
1779
- "test-scenarios/v1.10.0-behavior-evidence.json",
1780
- "scripts/collect-v1.10-evidence.js",
1781
- "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/README.md",
1782
- "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/before/project-status.json",
1783
- "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/after/project-status.json",
1784
- "init/xinyun-ai-init/rules/v1.10.2-contract.md",
1785
- "init/xinyun-ai-init/rules/v1.11.0-acceleration.md",
1786
- "init/xinyun-ai-init/templates/fixed-materialization.template.json",
1787
- "init/xinyun-ai-init/templates/bootstrap-snapshot.template.json",
1788
- "init/xinyun-ai-init/templates/initialization-stages.template.json",
1789
- "init/xinyun-ai-init/templates/initialization-cache.template.json",
1790
- "init/xinyun-ai-init/templates/parallelism.template.json",
1791
- ];
1792
- for (const file of requiredFiles) requireFile(file);
1793
-
1794
- const manifest = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
1795
- const projectIndex = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
1796
- const host = JSON.parse(readText("init/xinyun-ai-init/templates/host-capabilities.template.json"));
1797
- const projectStatus = JSON.parse(readText("init/xinyun-ai-init/templates/project-status.template.json"));
1798
- const preflight = JSON.parse(readText("init/xinyun-ai-init/templates/preflight-report.template.json"));
1799
- const onboarding = JSON.parse(readText("init/xinyun-ai-init/templates/onboarding-report.template.json"));
1800
- const baseline = JSON.parse(readText("init/xinyun-ai-init/templates/takeover-baseline.template.json"));
1801
- const controlPlane = JSON.parse(readText("init/xinyun-ai-init/templates/control-plane-index.template.json"));
1802
- const taskIndex = JSON.parse(readText("init/xinyun-ai-init/templates/task-index.template.json"));
1803
- const initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
1804
- const fixedMaterialization = JSON.parse(readText("init/xinyun-ai-init/templates/fixed-materialization.template.json"));
1805
- const bootstrapSnapshot = JSON.parse(readText("init/xinyun-ai-init/templates/bootstrap-snapshot.template.json"));
1806
- const initializationStages = JSON.parse(readText("init/xinyun-ai-init/templates/initialization-stages.template.json"));
1807
- const initializationCache = JSON.parse(readText("init/xinyun-ai-init/templates/initialization-cache.template.json"));
1808
- const parallelism = JSON.parse(readText("init/xinyun-ai-init/templates/parallelism.template.json"));
1809
- const currentTask = readText("init/xinyun-ai-init/templates/current-task.template.md");
1810
-
1811
- const paths = {
1812
- projectStatus: "xinyun-ai/project-status.json",
1813
- preflightReport: "xinyun-ai/preflight-report.json",
1814
- onboardingReport: "xinyun-ai/onboarding-report.json",
1815
- hostCapabilities: "xinyun-ai/host-capabilities.json",
1816
- takeoverBaseline: "xinyun-ai/index/takeover-baseline.json",
1817
- controlPlaneIndex: "xinyun-ai/index/control-plane-index.json",
1818
- };
1819
- for (const [key, expected] of Object.entries(paths)) {
1820
- addCheck(`v1.10 manifest path ${key}`, manifest.v110 && manifest.v110[key] === expected, expected);
1821
- addCheck(`v1.10 project-index path ${key}`, projectIndex.v110 && projectIndex.v110[key] === expected, expected);
1822
- }
1823
-
1824
- const projectStatuses = ["not-started", "initializing", "partial", "blocked", "ready"];
1825
- addCheck("v1.10 version metadata", manifest.xinyunAiVersion === CURRENT_VERSION && projectIndex.v110 && projectIndex.v110.projectStatusEnum.join(",") === projectStatuses.join(","), CURRENT_VERSION);
1826
- addCheck("v1.10 ready gate", manifest.v110 && manifest.v110.readyRequires && manifest.v110.readyRequires.includes("roleSessions") && manifest.v110.readyRequires.includes("sensitiveScan") && manifest.v110.requiredRoleSessionBlockedReason === "required-role-session-not-created", "required gates and blocked reason");
1827
- addCheck("v1.10 host capability schema", host.status === "unknown" && host.readyPolicy && host.readyPolicy.fakeSessionIdProhibited === true && host.readyPolicy.requiredCapabilities.length === 6, "conservative host defaults");
1828
- addCheck("v1.10 project status schema", projectStatus.projectStatus === "not-started" && projectStatus.executionEligible === false && JSON.stringify(projectStatus.projectStatusEnum) === JSON.stringify(projectStatuses), "not-started and executionEligible=false");
1829
- addCheck("v1.10 preflight schema", preflight.result === "not-run" && preflight.projectStatus === "not-started" && preflight.codeGraph.command === "codegraph init -i" && Array.isArray(preflight.unverifiedScope), "preflight defaults");
1830
- addCheck("v1.10 onboarding schema", onboarding.executionEligible === false && onboarding.roleSessionContract.realSessionIdRequired === true && onboarding.roleSessionContract.missingSessionReason === "required-role-session-not-created" && onboarding.requiredRoleIds.length === 5, "role session gate");
1831
- addCheck("v1.10 baseline schema", baseline.hashAlgorithm === "SHA-256" && baseline.git.writePerformed === false && baseline.businessFiles && baseline.controlFiles, "baseline hashes and read-only Git");
1832
- addCheck("v1.10 control-plane schema", controlPlane.atomicWriteContract && controlPlane.atomicWriteContract.tempFileRequired === true && controlPlane.atomicWriteContract.fsyncBeforeRename === true && controlPlane.idempotency && controlPlane.idempotency.duplicatePolicy === "reuse-and-audit", "atomic/idempotent control plane");
1833
- addCheck("v1.10 init-result database default", initResult.databaseAuthorization && initResult.databaseAuthorization.authorization === "not-requested" && initResult.databaseAuthorization.executionStatus === "needs-confirmation" && initResult.databaseAuthorization.redactionStatus === "verified" && initResult.databaseAuthorization.connected === false, "init-result database default");
1834
- addCheck("v1.10.2 identity separation", initResult.roleSessions && initResult.roleSessions.orchestratorIdentityType === "orchestrator-session" && initResult.roleSessions.identityMapping && ["hostThreadId", "hostSessionId", "projectSessionId", "orchestratorSessionId", "mappingStatus", "identityEvidence", "creationEvidence"].every((field) => Object.prototype.hasOwnProperty.call(initResult.roleSessions.identityMapping, field)), "host/project/orchestrator identity map");
1835
- addCheck("v1.10.2 result evidence schema", initResult.businessCodeChanged && initResult.businessCodeChanged.value === "unknown" && JSON.stringify(initResult.businessCodeChanged.evidenceSchema) === JSON.stringify(["evidenceType", "path", "beforeHash", "afterHash", "checkedAt"]) && initResult.roleSessions.realAiSessionVerified === false, "business-change evidence and real session gate");
1836
- addCheck("v1.10.2 task status source", taskIndex && taskIndex.statusConsistency && taskIndex.statusConsistency.sourceOfTruth === "task.status" && taskIndex.statusConsistency.illegalCombinationAction === "blocked-and-stop-write", "cross-file status source");
1837
- addCheck("v1.11 fixed materialization schema", fixedMaterialization.targetVersion === "1.11.0" && fixedMaterialization.hashAlgorithm === "SHA-256" && fixedMaterialization.atomicWrite && fixedMaterialization.atomicWrite.rename === true && fixedMaterialization.statusEnum.includes("conflict-pending"), "fixed template conflict contract");
1838
- addCheck("v1.11 initialization stages schema", initializationStages.stageStatusEnum.includes("recovery-required") && JSON.stringify(initializationStages.stages.map((stage) => stage.stageId)) === JSON.stringify(["preflight", "fixed-materialization", "control-plane", "codegraph", "bootstrap-snapshot", "role-sessions", "onboarding", "final-gate"]), "ordered initialization stages");
1839
- addCheck("v1.11 snapshot and cache schema", bootstrapSnapshot.scanBudget.maxDepth === 3 && Array.isArray(bootstrapSnapshot.unverifiedScope) && initializationCache.ttlHours === 24 && initializationCache.keyAlgorithm === "RFC8785-JCS-SHA-256", "bounded snapshot and expiring cache");
1840
- addCheck("v1.11 parallelism schema", parallelism.maxConcurrency === 3 && parallelism.requestedConcurrency === 3 && parallelism.queueOrder.includes("taskId"), "parallel role-session limit");
1841
- addCheck("v1.11 registry paths", manifest.v111 && projectIndex.v111 && manifest.v111.fixedMaterialization === "xinyun-ai/fixed-materialization.json" && projectIndex.v111.initializationStages === "xinyun-ai/initialization-stages.json" && manifest.v111.defaultRoleConcurrency === 3 && manifest.v111.cacheTtlHours === 24, "v1.11 manifest/project-index paths");
1842
- addCheck("v1.10 database defaults across control plane", manifest.v110 && projectIndex.v110 && JSON.stringify(manifest.v110.databaseDefault) === JSON.stringify(projectIndex.v110.databaseDefault) && JSON.stringify(manifest.v110.databaseDefault) === JSON.stringify({ authorization: "not-requested", executionStatus: "needs-confirmation", redactionStatus: "verified" }) && preflight.database && preflight.database.authorization === manifest.v110.databaseDefault.authorization && preflight.database.executionStatus === manifest.v110.databaseDefault.executionStatus && preflight.database.redactionStatus === manifest.v110.databaseDefault.redactionStatus && initResult.databaseAuthorization && initResult.databaseAuthorization.authorization === manifest.v110.databaseDefault.authorization && initResult.databaseAuthorization.executionStatus === manifest.v110.databaseDefault.executionStatus && initResult.databaseAuthorization.redactionStatus === manifest.v110.databaseDefault.redactionStatus, "database defaults agree across manifest/project-index/preflight/init-result");
1843
- const localDatabaseScope = ["*.sql", "*.ddl", "*.schema", "*.migration", "database/", "migrations/", "schema/", "models/"];
1844
- addCheck("v1.10 database local-file policy across control plane", preflight.database && initResult.databaseAuthorization && preflight.database.databaseAccessMode === "local-files-read-only" && initResult.databaseAuthorization.databaseAccessMode === "local-files-read-only" && preflight.database.legacyDatabaseAccessMode === "sql-only" && initResult.databaseAuthorization.legacyDatabaseAccessMode === "sql-only" && preflight.database.sqlExecutionMode === "generate-only" && initResult.databaseAuthorization.sqlExecutionMode === "generate-only" && preflight.database.connected === false && initResult.databaseAuthorization.connected === false && preflight.database.sqlExecuted === false && initResult.databaseAuthorization.sqlExecuted === false && JSON.stringify(preflight.database.localDatabaseFileScope) === JSON.stringify(localDatabaseScope) && JSON.stringify(initResult.databaseAuthorization.localDatabaseFileScope) === JSON.stringify(localDatabaseScope), "preflight and init-result database policy is inconsistent");
1845
- verifyV110CodeGraphContract(manifest, projectIndex, preflight, onboarding, initResult, currentTask);
1846
- verifyV110HostCapabilityContract(host, projectStatus);
1847
- const capabilityStatuses = ["available", "available-with-dependency", "unavailable", "permission-denied", "unknown", "not-checked", "not-verified", "failed"];
1848
- const capabilityStatusText = capabilityStatuses.join(" / ");
1849
- const projectGuide = readText("init/xinyun-ai-init/templates/project-guide.template.md");
1850
- addCheck("v1.10 capability enum across templates", projectIndex.tasking && projectIndex.tasking.stateMachine && JSON.stringify(projectIndex.tasking.stateMachine.capabilityStatus) === JSON.stringify(capabilityStatuses) && currentTask.includes(capabilityStatusText) && projectGuide.includes(capabilityStatusText), "complete capability status enum");
1851
-
1852
- requireIncludes("init/xinyun-ai-init/README.md", ["v1.10", "projectStatus=not-started/initializing/partial/blocked/ready", "required-role-session-not-created", "codegraph init -i", "authorization=not-requested", "executionStatus=needs-confirmation", "redactionStatus=verified", "不得进入业务代码开发"]);
1853
- requireIncludes("init/xinyun-ai-init/templates/core-rules.template.md", ["v1.10", "projectStatus", "executionEligible", "required-role-session-not-created", "host-capabilities", "takeover-baseline", "不得伪造 sessionId"]);
1854
- requireIncludes("init/xinyun-ai-init/rules/init-rules.md", ["v1.10", "preflight", "projectStatus", "codegraph init -i", "required-role-session-not-created", "sql-only"]);
1855
- requireIncludes("init/xinyun-ai-init/rules/upgrade-rules.md", ["v1.10", "projectStatus", "recovery", "不得覆盖", "required-role-session-not-created"]);
1856
- requireIncludes("init/xinyun-ai-init/rules/session-workbench.md", ["v1.10", "host capability", "真实 sessionId", "不得伪造 sessionId", "executionEligible"]);
1857
- requireIncludes("init/xinyun-ai-init/templates/current-task.template.md", ["statusSource:xinyun-ai/manifest.json", "sourceRevision:", "indexScope:", "unindexedScope:"]);
1858
- requireIncludes("init/xinyun-ai-init/templates/project-guide.template.md", ["available / available-with-dependency / unavailable / permission-denied / unknown / not-checked / not-verified / failed"]);
1859
- requireIncludes("test-scenarios/v1.10.0-scenarios.md", ["## 120.", "## 123.", "## 123-A.", "## 121-A.", "## 121-B.", "## 128.", "## 128-A.", "## 130.", "## 133.", "projectStatus", "not-verified", "available-with-dependency", "状态源缺失"]);
1860
-
1861
- verifyV110BehaviorEvidence();
1862
- }
1863
-
1864
- function verifyV110CodeGraphContract(manifest, projectIndex, preflight, onboarding, initResult, currentTask) {
1865
- const source = manifest.codeGraphRequired;
1866
- const indexSource = projectIndex.codeGraphRequired;
1867
- const summaryFields = ["codeGraphRecordId", "statusSource", "status", "sourceRevision", "indexScope", "unindexedScope", "failureReason", "evidence"];
1868
- const sameSummary = (record) => record && summaryFields.every((field) => JSON.stringify(record[field]) === JSON.stringify(source[field]));
1869
- addCheck("v1.10 CodeGraph manifest is the status source", source && source.statusSource === "xinyun-ai/manifest.json" && source.required === true, "manifest.codeGraphRequired");
1870
- addCheck("v1.10 CodeGraph project-index summary", sameSummary(indexSource), "project-index.codeGraphRequired mirrors manifest");
1871
- addCheck("v1.10 CodeGraph preflight summary", sameSummary(preflight.codeGraph), "preflight.codeGraph mirrors manifest");
1872
- addCheck("v1.10 CodeGraph onboarding summary", onboarding.codeGraphRecordId === source.codeGraphRecordId && sameSummary({ ...onboarding.codeGraph, codeGraphRecordId: onboarding.codeGraphRecordId }), "onboarding codeGraph mirrors manifest");
1873
- addCheck("v1.10 CodeGraph init-result summary", sameSummary(initResult.codeGraph), "init-result.codeGraph mirrors manifest");
1874
- addCheck("v1.10 CodeGraph source fields", ["sourceRevision", "indexScope", "unindexedScope", "failureReason", "evidence"].every((field) => Object.prototype.hasOwnProperty.call(source, field)), "status source includes range and failure evidence");
1875
- addCheck("v1.10 CodeGraph current-task fields", ["statusSource:xinyun-ai/manifest.json", "sourceRevision:", "indexScope:", "unindexedScope:", "failureReason:"].every((field) => currentTask.includes(field)), "current-task mirrors CodeGraph summary");
1876
- }
1877
-
1878
- function verifyV110HostCapabilityContract(host, projectStatus) {
1879
- const requiredFields = ["capabilityId", "detectionMethod", "status", "evidence", "dependencyStatus", "fallbackPlan", "usedTools", "unusedTools", "unverifiedScope", "failureReason", "checkedAt"];
1880
- const statuses = ["available", "available-with-dependency", "unavailable", "permission-denied", "unknown", "not-checked", "not-verified", "failed"];
1881
- const dependencyStatuses = ["not-required", "required", "authorized", "not-authorized", "unknown"];
1882
- const capabilities = host && host.capabilities ? Object.values(host.capabilities) : [];
1883
- addCheck("v1.10 host capability status enum", JSON.stringify(host.statusEnum) === JSON.stringify(statuses), "all host capability statuses");
1884
- addCheck("v1.10 host dependency status enum", JSON.stringify(host.dependencyStatusEnum) === JSON.stringify(dependencyStatuses), "all dependency statuses");
1885
- addCheck("v1.10 host capability minimum fields", capabilities.length === 6 && capabilities.every((capability) => requiredFields.every((field) => Object.prototype.hasOwnProperty.call(capability, field))), "six capabilities have the minimum evidence contract");
1886
- addCheck("v1.10 host dependency gate", host.readyPolicy && host.readyPolicy.availableWithDependencyBlocksReady === true && host.readyPolicy.notVerifiedBlocksReady === true && host.readyPolicy.blockedStatuses.includes("not-verified") && host.readyPolicy.dependencyRequiredStatus === "authorized" && host.readyPolicy.fakeSessionIdProhibited === true, "dependency authorization and not-verified are required blockers");
1887
- const blockedStatuses = ["unknown", "unavailable", "permission-denied", "failed", "available-with-dependency", "not-checked", "not-verified"];
1888
- addCheck("v1.10 project ready blocked statuses", projectStatus.readyPolicy && blockedStatuses.every((status) => projectStatus.readyPolicy.requiredCapabilityBlockedStatuses.includes(status)) && projectStatus.readyPolicy.availableWithDependencyRequires.includes("dependencyStatus=authorized"), "required capability failures cannot reach ready");
1889
- }
1890
-
1891
- function verifyV110BehaviorEvidence() {
1892
- const relativePath = "test-scenarios/v1.10.0-behavior-evidence.json";
1893
- let report;
1894
- try {
1895
- report = JSON.parse(readText(relativePath));
1896
- addCheck("v1.10 behavior evidence JSON parse", true, "JSON parse");
1897
- } catch (error) {
1898
- addCheck("v1.10 behavior evidence JSON parse", false, error.message);
1899
- return;
1900
- }
1901
- const scenarios = Array.isArray(report.scenarios) ? report.scenarios : [];
1902
- const expectedIds = Array.from({ length: 14 }, (_, index) => 120 + index);
1903
- const requiredFields = ["scenarioId", "sessionId", "input", "expectedOutput", "actualOutput", "beforeSnapshotHash", "afterSnapshotHash", "changedFiles", "forbiddenOperations", "evidence", "sensitiveScan", "result", "recordedAt"];
1904
- addCheck("v1.10 behavior evidence source", report.evidenceType === "not-verified" && report.executionMode === "host-capability-unavailable" && report.realAiSessionVerified === false && report.publishBlocked === true, "not-verified evidence is required when role sessions are unavailable");
1905
- addCheck("v1.10 behavior evidence fixture", report.fixturePath === "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture" && fs.existsSync(path.join(root, report.fixturePath, "before", "project-status.json")) && fs.existsSync(path.join(root, report.fixturePath, "after", "project-status.json")), "persistent fixture boundary exists");
1906
- addCheck("v1.10 behavior evidence IDs", JSON.stringify(scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(expectedIds), "scenarios 120-133");
1907
- for (const scenario of scenarios) {
1908
- const prefix = `v1.10 behavior evidence ${scenario.scenarioId}`;
1909
- addCheck(`${prefix} required fields`, requiredFields.every((field) => Object.prototype.hasOwnProperty.call(scenario, field)), "required evidence fields");
1910
- addCheck(`${prefix} not verified`, scenario.result === "not-verified" && scenario.sessionId === null && scenario.actualOutput === "not-verified", "no real session must remain not-verified");
1911
- addCheck(`${prefix} forbidden operations`, scenario.forbiddenOperations && Object.values(scenario.forbiddenOperations).every((value) => value === false), "forbidden operations must not run");
1912
- addCheck(`${prefix} sensitive scan`, scenario.sensitiveScan && scenario.sensitiveScan.status === "pass" && Array.isArray(scenario.sensitiveScan.matches) && scenario.sensitiveScan.matches.length === 0, "sensitive scan");
1913
- }
1914
- }
1915
-
1916
- function verifyV112Contracts() {
1917
- const requiredFiles = [
1918
- "init/xinyun-ai-init/rules/v1.12.0-recovery.md",
1919
- "init/xinyun-ai-init/templates/host-preflight.template.json",
1920
- "init/xinyun-ai-init/templates/initialization-recovery.template.json",
1921
- "init/xinyun-ai-init/templates/manual-session-binding.template.json",
1922
- "init/xinyun-ai-init/templates/shared-project-snapshot.template.json",
1923
- "init/xinyun-ai-init/templates/initialization-timing.template.json",
1924
- "test-scenarios/v1.12.0-scenarios.md",
1925
- "test-scenarios/v1.12.0-behavior-evidence.json",
1926
- ];
1927
- for (const file of requiredFiles) requireFile(file);
1928
-
1929
- let manifest;
1930
- let projectIndex;
1931
- let host;
1932
- let recovery;
1933
- let binding;
1934
- let snapshot;
1935
- let timing;
1936
- let initResult;
1937
- try {
1938
- manifest = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
1939
- projectIndex = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
1940
- host = JSON.parse(readText("init/xinyun-ai-init/templates/host-preflight.template.json"));
1941
- recovery = JSON.parse(readText("init/xinyun-ai-init/templates/initialization-recovery.template.json"));
1942
- binding = JSON.parse(readText("init/xinyun-ai-init/templates/manual-session-binding.template.json"));
1943
- snapshot = JSON.parse(readText("init/xinyun-ai-init/templates/shared-project-snapshot.template.json"));
1944
- timing = JSON.parse(readText("init/xinyun-ai-init/templates/initialization-timing.template.json"));
1945
- initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
1946
- } catch (error) {
1947
- addCheck("v1.12 template JSON parse", false, error.message);
1948
- return;
1949
- }
1950
-
1951
- const paths = ["hostPreflight", "initializationRecovery", "manualSessionBindings", "sharedProjectSnapshot", "initializationTiming"];
1952
- addCheck("v1.12 manifest/project-index registration", manifest.v112 && projectIndex.v112 && paths.every((key) => manifest.v112[key] === projectIndex.v112[key]), "v1.12 paths must match across index files");
1953
- addCheck("v1.12 capability flags", ["hostPreflightRecovery", "manualRoleSessionBinding", "codeGraphIncrementalReuse", "sharedProjectSnapshot", "initializationTiming"].every((key) => manifest.capabilities && manifest.capabilities[key] === true), "v1.12 manifest capabilities");
1954
- addCheck("v1.12 capability enum consistency", JSON.stringify(manifest.v112.hostCapabilityStatusEnum) === JSON.stringify(projectIndex.v112.hostCapabilityStatusEnum) && host.capabilityStatusEnum.every((status) => manifest.v112.hostCapabilityStatusEnum.includes(status)), "host capability statuses are consistent");
1955
- addCheck("v1.12 required host capabilities", JSON.stringify(host.requiredCapabilities) === JSON.stringify(manifest.v112.preflightRequiredCapabilities) && host.capabilities && manifest.v112.preflightRequiredCapabilities.every((id) => host.capabilities[id]), "all seven host capabilities are required");
1956
- const capabilityFields = ["capabilityId", "detectionMethod", "status", "evidence", "dependencyStatus", "fallbackPlan", "usedTools", "unusedTools", "unverifiedScope", "failureReason", "checkedAt"];
1957
- addCheck("v1.12 host capability evidence fields", Object.values(host.capabilities).every((capability) => capabilityFields.every((field) => Object.prototype.hasOwnProperty.call(capability, field))), "host capability minimum evidence fields");
1958
- addCheck("v1.12 conservative preflight default", host.status === "not-checked" && host.readyGate && host.readyGate.allRequiredCapabilitiesPassed === false && host.readyGate.unknownBlocksReady === true && host.readyGate.fakeSessionIdProhibited === true && host.realSessionIdEvidence.verified === false, "preflight cannot default to ready");
1959
- addCheck("v1.12 task-first recovery", recovery.status === "not-started" && recovery.reuseContract.reuseTaskId === true && recovery.reuseContract.reuseRoleTaskIds === true && recovery.reuseContract.incrementAttempt === true && recovery.reuseContract.createDuplicateTasks === false && recovery.resumeTriggers.every((trigger) => manifest.v112.resumeConfirmationPhrases.includes(trigger)), "resume reuses IDs and prevents duplicate tasks");
1960
- addCheck("v1.12 atomic recovery", recovery.atomicWrite && recovery.atomicWrite.tempFileRequired === true && recovery.atomicWrite.fsyncBeforeRename === true && recovery.atomicWrite.rename === true && recovery.atomicWrite.recoveryOnFailure === true, "recovery writes are atomic");
1961
- addCheck("v1.12 manual binding gate", binding.sessionId === null && binding.bindingStatus === "pending" && binding.executionEligible === false && binding.fakeSessionIdProhibited === true && binding.evidenceRequiredFields.includes("sessionId") && binding.evidenceRequiredFields.includes("interactionHash"), "manual binding requires real evidence");
1962
- addCheck("v1.12 snapshot reuse", snapshot.generatedOnce === false && snapshot.snapshotStatus === "not-checked" && snapshot.reuseDecision === "unknown" && snapshot.reusedByRoleIds.length === 0 && manifest.v112.projectSnapshotReusePolicy === "reuse-until-business-or-codegraph-hash-changes", "one shared snapshot with explicit refresh triggers");
1963
- addCheck("v1.12 timing schema", JSON.stringify(timing.stageRequiredFields) === JSON.stringify(manifest.v112.stageTimingRequiredFields) && timing.attempt === 1 && timing.stages.length === 0, "stage duration and recovery evidence fields");
1964
- addCheck("v1.12 init-result links", initResult.targetVersion === CURRENT_VERSION && initResult.v112 && paths.every((key) => initResult.v112[`${key}Path`] === manifest.v112[key]) && initResult.v112.duplicateTasksCreated === 0 && initResult.v112.realSessionIdRequired === true, "init-result links v1.12 control files");
1965
- const scenarioText = readText("test-scenarios/v1.12.0-scenarios.md");
1966
- addCheck("v1.12 scenarios", Array.from({ length: 12 }, (_, index) => 134 + index).every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("sessionId=null") && scenarioText.includes("确认继续初始化"), "v1.12 scenarios 134-145");
1967
- let behaviorEvidence;
1968
- try {
1969
- behaviorEvidence = JSON.parse(readText("test-scenarios/v1.12.0-behavior-evidence.json"));
1970
- } catch (error) {
1971
- addCheck("v1.12 behavior evidence JSON", false, error.message);
1972
- behaviorEvidence = null;
1973
- }
1974
- const behaviorScenarios = behaviorEvidence && Array.isArray(behaviorEvidence.scenarios) ? behaviorEvidence.scenarios : [];
1975
- addCheck("v1.12 behavior evidence honest gate", behaviorEvidence && behaviorEvidence.evidenceType === "not-verified" && behaviorEvidence.realAiSessionVerified === false && behaviorEvidence.publishBlocked === true && behaviorEvidence.sessionIdPolicy.includes("sessionId remains null"), "real host behavior is not fabricated");
1976
- addCheck("v1.12 behavior evidence IDs", JSON.stringify(behaviorScenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(Array.from({ length: 12 }, (_, index) => 134 + index)), "behavior evidence covers 134-145");
1977
- addCheck("v1.12 behavior evidence not-verified", behaviorScenarios.length === 12 && behaviorScenarios.every((scenario) => scenario.sessionId === null && scenario.result === "not-verified" && scenario.actualOutput === "not-verified" && scenario.sensitiveScan && scenario.sensitiveScan.status === "pass" && scenario.sensitiveScan.matches.length === 0), "unavailable host remains blocked without fake IDs");
1978
- const releasePath = path.join(root, "version-plans/releases/v1.12.0.md");
1979
- if (fs.existsSync(releasePath)) {
1980
- const releaseText = readText("version-plans/releases/v1.12.0.md");
1981
- addCheck("v1.12 release exclusions", releaseText.includes("No automatic host login") && releaseText.includes("no database connection") && releaseText.includes("no npm publish"), "v1.12 safety and scope exclusions");
1982
- } else {
1983
- addCheck("v1.12 release exclusions", true, "source-only release material is not required in tarball");
1984
- }
1985
- addCheck("v1.12 rule contract", readText("init/xinyun-ai-init/rules/v1.12.0-recovery.md").includes("available-with-dependency") && readText("init/xinyun-ai-init/rules/v1.12.0-recovery.md").includes("shared-project-snapshot.json"), "v1.12 recovery rule is present");
1986
- }
1987
-
1988
- function verifyV1121Contracts() {
1989
- const requiredFiles = [
1990
- "init/xinyun-ai-init/rules/v1.12.1-provider-session-binding.md",
1991
- "init/xinyun-ai-init/templates/provider-session-binding.template.json",
1992
- "test-scenarios/v1.12.1-scenarios.md",
1993
- "test-scenarios/v1.12.1-behavior-evidence.json",
1994
- ];
1995
- for (const file of requiredFiles) requireFile(file);
1996
-
1997
- let manifest;
1998
- let projectIndex;
1999
- let initResult;
2000
- let binding;
2001
- let manual;
2002
- let evidence;
2003
- try {
2004
- manifest = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
2005
- projectIndex = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
2006
- initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
2007
- binding = JSON.parse(readText("init/xinyun-ai-init/templates/provider-session-binding.template.json"));
2008
- manual = JSON.parse(readText("init/xinyun-ai-init/templates/manual-session-binding.template.json"));
2009
- evidence = JSON.parse(readText("test-scenarios/v1.12.1-behavior-evidence.json"));
2010
- } catch (error) {
2011
- addCheck("v1.12.1 template JSON parse", false, error.message);
2012
- return;
2013
- }
2014
-
2015
- const bindingStatuses = ["pending", "validating", "bound", "blocked", "rejected", "released", "conflict", "recovery-required"];
2016
- const bindingModes = ["auto-created", "auto-reused", "manual", "recovery", "local-degraded"];
2017
- const identityFields = ["providerSessionId", "projectRootHash", "workspaceScope", "roleId", "taskId", "title", "cwd", "source", "verifiedAt", "evidenceHash"];
2018
- const interactionFields = ["sendReceipt", "receiveReceipt", "transcriptHash", "messageCount", "recordedAt", "evidenceHash"];
2019
- const bindingFields = ["provider", "providerSessionId", "roleId", "taskId", "projectRootHash", "workspaceScope", "title", "cwd", "createdAt", "identityEvidence", "interactionEvidence", "bindingMode", "bindingStatus", "boundBy", "boundAt"];
2020
- addCheck("v1.12.1 version metadata", manifest.xinyunAiVersion === CURRENT_VERSION && initResult.targetVersion === CURRENT_VERSION && binding.targetVersion === undefined, CURRENT_VERSION);
2021
- addCheck("v1.12.1 registry paths", manifest.v1121 && projectIndex.v1121 && manifest.v1121.providerBindings === projectIndex.v1121.providerBindings && manifest.v1121.providerBindingTemplate === projectIndex.v1121.providerBindingTemplate && manifest.roleSessions.providerSessionBindings === projectIndex.roleSessions.providerSessionBindings, "manifest/project-index provider binding paths");
2022
- addCheck("v1.12.1 binding fields", bindingFields.every((field) => Object.prototype.hasOwnProperty.call(binding, field)), "canonical provider binding fields");
2023
- addCheck("v1.12.1 binding enums", JSON.stringify(binding.bindingStatusEnum) === JSON.stringify(bindingStatuses) && bindingModes.includes(binding.bindingMode), "binding modes and statuses");
2024
- addCheck("v1.12.1 evidence fields", identityFields.every((field) => Object.prototype.hasOwnProperty.call(binding.identityEvidence, field)) && interactionFields.every((field) => Object.prototype.hasOwnProperty.call(binding.interactionEvidence, field)), "identity and interaction evidence fields");
2025
- addCheck("v1.12.1 conservative template", binding.providerSessionId === null && binding.bindingStatus === "pending" && binding.executionEligible === false && binding.fakeProviderSessionIdProhibited === true, "provider ID and execution defaults");
2026
- addCheck("v1.12.1 manual compatibility", manual.providerSessionId === null && manual.bindingMode === "manual" && manual.executionEligible === false && manual.fakeSessionIdProhibited === true && manual.evidenceRequiredFields.includes("providerSessionId"), "manual binding remains gated");
2027
- addCheck("v1.12.1 init-result link", initResult.v1121 && initResult.v1121.providerSessionBindingsPath === manifest.v1121.providerBindings && initResult.v1121.providerSessionBindingTemplate === manifest.v1121.providerBindingTemplate && initResult.v1121.fakeProviderSessionIdProhibited === true, "init-result provider binding link");
2028
- const scenarioText = readText("test-scenarios/v1.12.1-scenarios.md");
2029
- const scenarioIds = Array.from({ length: 13 }, (_, index) => 146 + index);
2030
- addCheck("v1.12.1 scenarios", scenarioIds.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("providerSessionId=null"), "scenarios 146-158");
2031
- addCheck("v1.12.1 honest behavior evidence", evidence.version === "1.12.1" && evidence.evidenceType === "not-verified" && evidence.realAiSessionVerified === false && evidence.publishBlocked === true && JSON.stringify(evidence.scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(scenarioIds), "real host evidence status");
2032
- addCheck("v1.12.1 no fabricated IDs", evidence.scenarios.every((scenario) => scenario.providerSessionId === null && scenario.sessionId === null && scenario.result === "not-verified" && scenario.sensitiveScan && scenario.sensitiveScan.status === "pass" && scenario.sensitiveScan.matches.length === 0), "provider session IDs remain null without host evidence");
2033
- const ruleText = readText("init/xinyun-ai-init/rules/v1.12.1-provider-session-binding.md");
2034
- addCheck("v1.12.1 rule contract", ["providerSessionId", "canonical", "identityEvidence", "interactionEvidence", "exclusive occupancy", "Do not fabricate"].every((term) => ruleText.includes(term)), "provider session rule contract");
2035
- }
2036
-
2037
- function verifyV113Contracts() {
2038
- const requiredFiles = [
2039
- "init/xinyun-ai-init/rules/v1.13.0-host-adapter.md",
2040
- "init/xinyun-ai-init/templates/provider-adapter.template.json",
2041
- "init/xinyun-ai-init/templates/manual-session-recovery.template.json",
2042
- "init/xinyun-ai-init/templates/initialization-change-report.template.json",
2043
- "init/xinyun-ai-init/templates/role-session-binding.template.json",
2044
- "init/xinyun-ai-init/templates/provider-session-binding.template.json",
2045
- "init/xinyun-ai-init/templates/task-index.template.json",
2046
- "init/xinyun-ai-init/templates/team/assignments.json",
2047
- "test-scenarios/v1.13.0-scenarios.md",
2048
- "test-scenarios/v1.13.0-behavior-evidence.json",
2049
- ];
2050
- for (const file of requiredFiles) requireFile(file);
2051
-
2052
- let manifest;
2053
- let projectIndex;
2054
- let initResult;
2055
- let adapter;
2056
- let recovery;
2057
- let changeReport;
2058
- let roleBinding;
2059
- let providerBinding;
2060
- let taskIndex;
2061
- let assignments;
2062
- let evidence;
2063
- try {
2064
- manifest = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
2065
- projectIndex = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
2066
- initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
2067
- adapter = JSON.parse(readText("init/xinyun-ai-init/templates/provider-adapter.template.json"));
2068
- recovery = JSON.parse(readText("init/xinyun-ai-init/templates/manual-session-recovery.template.json"));
2069
- changeReport = JSON.parse(readText("init/xinyun-ai-init/templates/initialization-change-report.template.json"));
2070
- roleBinding = JSON.parse(readText("init/xinyun-ai-init/templates/role-session-binding.template.json"));
2071
- providerBinding = JSON.parse(readText("init/xinyun-ai-init/templates/provider-session-binding.template.json"));
2072
- taskIndex = JSON.parse(readText("init/xinyun-ai-init/templates/task-index.template.json"));
2073
- assignments = JSON.parse(readText("init/xinyun-ai-init/templates/team/assignments.json"));
2074
- evidence = JSON.parse(readText("test-scenarios/v1.13.0-behavior-evidence.json"));
2075
- } catch (error) {
2076
- addCheck("v1.13 template JSON parse", false, error.message);
2077
- return;
2078
- }
2079
-
2080
- const paths = ["providerAdapter", "manualSessionRecovery", "initializationChangeReport"];
2081
- addCheck("v1.13 manifest/project-index registration", manifest.v113 && projectIndex.v113 && paths.every((key) => manifest.v113[key] === projectIndex.v113[key]), "v1.13 paths must match across index files");
2082
- addCheck("v1.13 init-result registration", initResult.v113 && paths.every((key) => initResult.v113[`${key}Path`] === manifest.v113[key]), "init-result links all v1.13 control files");
2083
- const userDecisions = ["manual-create", "defer", "redetect"];
2084
- const decisionStatuses = ["not-asked", "awaiting-user", "selected", "processing", "completed", "blocked"];
2085
- const decisionFields = ["userDecision", "requiredRoleCount", "createdRoleCount", "remainingRoleIds", "decisionStatus", "decidedAt", "nextAction", "decisionEvidence"];
2086
- addCheck("v1.13 decision registry", manifest.v113 && projectIndex.v113 && JSON.stringify(manifest.v113.userDecisionEnum) === JSON.stringify(userDecisions) && JSON.stringify(projectIndex.v113.userDecisionEnum) === JSON.stringify(userDecisions) && JSON.stringify(manifest.v113.decisionStatusEnum) === JSON.stringify(decisionStatuses) && JSON.stringify(projectIndex.v113.decisionStatusEnum) === JSON.stringify(decisionStatuses), "decision enums match across registries");
2087
- addCheck("v1.13 decision defaults", decisionFields.every((field) => Object.prototype.hasOwnProperty.call(initResult.v113, field)) && initResult.v113.requiredRoleCount === 5 && initResult.v113.createdRoleCount === 0 && initResult.v113.decisionStatus === "not-asked" && initResult.v113.userDecision === null, "init-result preserves the one-time decision gate");
2088
- const sessionCreationStatuses = ["not-asked", "awaiting-confirmation", "approved", "deferred", "processing", "completed", "blocked"];
2089
- addCheck("v1.13 task-first session gate", recovery.taskFirstSessionGate && initResult.v113.sessionCreationDecision && recovery.taskFirstSessionGate.mainTaskCreatedBeforeSession === true && recovery.taskFirstSessionGate.roleTasksCreatedBeforeSession === true && recovery.taskFirstSessionGate.sessionIdsRemainNullUntilDecision === true && JSON.stringify(recovery.taskFirstSessionGate.sessionCreationStatusEnum) === JSON.stringify(sessionCreationStatuses) && JSON.stringify(initResult.v113.sessionCreationDecision.statusEnum) === JSON.stringify(sessionCreationStatuses) && initResult.v113.sessionCreationDecision.status === "awaiting-confirmation" && initResult.v113.sessionCreationDecision.sessionIdsRemainNullUntilDecision === true, "tasks are created before user-approved session creation");
2090
- const decisionMetadataFields = ["decisionId", "actor", "source"];
2091
- const decisionEvidenceFields = ["decisionId", "userDecision", "actor", "source", "decidedAt", "inputHash", "evidenceHash"];
2092
- const recoveryText = readText("init/xinyun-ai-init/templates/manual-session-recovery.template.json");
2093
- addCheck("v1.13 decision metadata", decisionMetadataFields.every((field) => Object.prototype.hasOwnProperty.call(recovery, field) && Object.prototype.hasOwnProperty.call(initResult.v113, field)) && decisionEvidenceFields.every((field) => recovery.decisionEvidenceSchema.includes(field) && initResult.v113.decisionEvidenceSchema.includes(field)) && (recoveryText.match(/^ \"nextAction\"/gm) || []).length === 1, "decision identity fields are mirrored and top-level nextAction is singular");
2094
- const capabilities = ["createRealSession", "reuseExistingSession", "sendTask", "receiveResult", "querySessionStatus", "recoverSession", "closeSession", "controlFileReadWrite"];
2095
- addCheck("v1.13 required capabilities", JSON.stringify(manifest.v113.preflightRequiredCapabilities) === JSON.stringify(capabilities), "all eight preflight capabilities are registered");
2096
-
2097
- const statusEnum = ["not-checked", "checking", "available", "available-with-dependency", "unavailable", "permission-denied", "unknown", "failed", "not-verified"];
2098
- addCheck("v1.13 adapter status enum", JSON.stringify(adapter.statusEnum) === JSON.stringify(statusEnum), "adapter status enum is complete");
2099
- addCheck("v1.13 adapter operations", capabilities.every((id) => Object.values(adapter.operations).some((operation) => operation.operationId === id)), "all required adapter operations exist");
2100
- addCheck("v1.13 canonical session ID", adapter.canonicalSessionIdField === "providerSessionId" && adapter.canonicalSessionIdSource === "provider-supported-session-api-response" && adapter.fakeSessionIdProhibited === true && adapter.ordinaryThreadIdProhibited === true, "only provider canonical IDs can bind sessions");
2101
- addCheck("v1.13 adapter ready gate", adapter.readyGate.includes("identity") && adapter.readyGate.includes("interaction") && adapter.readyGate.includes("all required operations available"), "adapter ready gate requires evidence");
2102
-
2103
- const sessionIdentityFields = ["hostThreadId", "hostSessionId", "providerSessionId", "projectSessionId", "sessionId", "orchestratorSessionId"];
2104
- const requiredHostEvidence = ["create-or-reuse", "send", "receive", "query-status", "recover", "close"];
2105
- const identityContractMatches = JSON.stringify(manifest.v113.sessionIdentityFields) === JSON.stringify(sessionIdentityFields)
2106
- && JSON.stringify(projectIndex.v113.sessionIdentityFields) === JSON.stringify(sessionIdentityFields)
2107
- && JSON.stringify(taskIndex.sessionIdentityContract.fields) === JSON.stringify(sessionIdentityFields)
2108
- && JSON.stringify(manifest.v113.requiredHostEvidence) === JSON.stringify(requiredHostEvidence)
2109
- && JSON.stringify(projectIndex.v113.requiredHostEvidence) === JSON.stringify(requiredHostEvidence)
2110
- && JSON.stringify(taskIndex.sessionIdentityContract.requiredHostEvidence) === JSON.stringify(requiredHostEvidence);
2111
- addCheck("v1.13 session identity registry", identityContractMatches && manifest.v113.canonicalSessionIdentity === "providerSessionId" && projectIndex.v113.canonicalSessionIdentity === "providerSessionId" && taskIndex.sessionIdentityContract.canonicalField === "providerSessionId", "session identity fields and canonical source match");
2112
- addCheck("v1.13 binding identity mapping", roleBinding.identityMapping.equivalenceRule.includes("sessionId equals providerSessionId") && providerBinding.identityMapping.equivalenceRule.includes("sessionId equals providerSessionId") && roleBinding.identityMapping.providerSessionId === null && providerBinding.providerSessionId === null && roleBinding.sessionId === null && providerBinding.sessionId === null, "role/provider bindings start unverified and use one mapping rule");
2113
- addCheck("v1.13 assignment identity contract", assignments.recordContract.requiredFields.includes("projectSessionId") && assignments.recordContract.requiredFields.includes("hostThreadId") && assignments.recordContract.requiredFields.includes("hostSessionId") && assignments.recordContract.requiredFields.includes("identityMapping") && assignments.recordContract.sessionBindingRule.includes("create-or-reuse") && assignments.recordContract.sessionBindingRule.includes("close") && assignments.recordContract.sessionBindingRule.includes("providerSessionId"), "assignments enforce canonical provider evidence");
2114
-
2115
- const roleIds = ["project-owner", "project-product", "chief-engineer", "programmer", "test-reviewer"];
2116
- addCheck("v1.13 manual recovery roles", JSON.stringify(recovery.roles.map((role) => role.roleId)) === JSON.stringify(roleIds) && recovery.roles.every((role) => role.providerSessionId === null && role.bindingStatus === "pending" && role.sessionTitle && role.responsibility && role.firstTaskPrompt), "five manual recovery entries are conservative and actionable");
2117
- addCheck("v1.13 recovery contract", recovery.reuseContract && recovery.reuseContract.reuseTaskId === true && recovery.reuseContract.reuseRoleTaskId === true && recovery.reuseContract.incrementAttempt === true && recovery.reuseContract.createDuplicateTasks === false && recovery.reuseContract.replaceUnverifiedSession === false && recovery.fakeProviderSessionIdProhibited === true, "recovery reuses IDs and forbids fabricated sessions");
2118
- const bindingFields = ["provider", "providerSessionId", "projectRootHash", "workspaceScope", "roleId", "taskId", "title", "cwd", "boundBy", "boundAt", "identityEvidence", "interactionEvidence"];
2119
- addCheck("v1.13 recovery binding fields", bindingFields.every((field) => recovery.bindingRequiredFields.includes(field)), "manual binding fields are complete");
2120
-
2121
- const originEnum = ["initialization-created", "initialization-updated", "pre-existing-user-change", "control-plane-only"];
2122
- addCheck("v1.13 change origin contract", JSON.stringify(changeReport.changeOriginEnum) === JSON.stringify(originEnum) && changeReport.businessCodeChanged.value === "unknown" && changeReport.requiredChangeFields.includes("beforeHash") && changeReport.requiredChangeFields.includes("afterHash"), "initialization changes are separated from user changes");
2123
-
2124
- const expectedIds = Array.from({ length: 27 }, (_, index) => 159 + index);
2125
- const scenarioText = readText("test-scenarios/v1.13.0-scenarios.md");
2126
- addCheck("v1.13 scenario catalog", expectedIds.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("manual-create") && scenarioText.includes("create-and-onboard") && scenarioText.includes("decisionStatus"), "scenarios 159-185 are catalogued with task-first session decisions");
2127
- addCheck("v1.13 behavior evidence honest gate", evidence.version === "1.13.1" && evidence.evidenceType === "not-verified" && evidence.realAiSessionVerified === false && evidence.publishBlocked === true && evidence.sessionId === null && evidence.providerSessionId === null && JSON.stringify(evidence.scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(expectedIds), "unavailable host evidence remains blocked without fake IDs");
2128
- const evidenceFields = ["scenarioId", "input", "expectedOutput", "actualOutput", "beforeSnapshotHash", "afterSnapshotHash", "changedFiles", "controlFilesChanged", "forbiddenOperations", "evidence", "sensitiveScan", "result", "recordHash", "recordedAt"];
2129
- addCheck("v1.13 behavior evidence fields", evidence.scenarios.length === expectedIds.length && JSON.stringify(evidence.scenarioRequiredFields) === JSON.stringify(evidenceFields) && evidence.scenarios.every((scenario) => evidenceFields.every((field) => Object.prototype.hasOwnProperty.call(scenario, field)) && scenario.evidenceType === "not-verified" && scenario.recordHash === "not-recorded" && scenario.result === "not-verified" && scenario.sessionId === null && scenario.providerSessionId === null && scenario.sensitiveScan && scenario.sensitiveScan.status === "pass" && scenario.sensitiveScan.matches.length === 0), "scenarios 159-181 have auditable fields and remain explicitly not-verified");
2130
- const ruleText = readText("init/xinyun-ai-init/rules/v1.13.0-host-adapter.md");
2131
- addCheck("v1.13 rule contract", ["providerSessionId", "Ordinary", "Manual recovery", "manual-create", "defer", "redetect", "decisionStatus=awaiting-user", "pre-existing-user-change", "No provider login/install"].every((term) => ruleText.includes(term)), "host adapter and recovery decision rules are present");
2132
- }
2133
-
2134
- function verifyV114Contracts() {
2135
- const requiredFiles = [
2136
- "init/xinyun-ai-init/rules/v1.14.0-agent-core.md",
2137
- "init/xinyun-ai-init/templates/agent-profile.template.json",
2138
- "init/xinyun-ai-init/templates/agent-capabilities.template.json",
2139
- "init/xinyun-ai-init/templates/takeover-gate.template.json",
2140
- "init/xinyun-ai-init/templates/orchestrator.template.json",
2141
- "init/xinyun-ai-init/templates/task-graph.template.json",
2142
- "init/xinyun-ai-init/templates/handoff.template.json",
2143
- "init/xinyun-ai-init/templates/final-delivery.template.json",
2144
- "test-scenarios/v1.14.0-scenarios.md",
2145
- "test-scenarios/v1.14.0-behavior-evidence.json",
2146
- ];
2147
- requiredFiles.forEach(requireFile);
2148
-
2149
- const manifest = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
2150
- const projectIndex = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
2151
- const projectStatus = JSON.parse(readText("init/xinyun-ai-init/templates/project-status.template.json"));
2152
- const initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
2153
- const taskIndex = JSON.parse(readText("init/xinyun-ai-init/templates/task-index.template.json"));
2154
- const profile = JSON.parse(readText("init/xinyun-ai-init/templates/agent-profile.template.json"));
2155
- const capabilities = JSON.parse(readText("init/xinyun-ai-init/templates/agent-capabilities.template.json"));
2156
- const takeover = JSON.parse(readText("init/xinyun-ai-init/templates/takeover-gate.template.json"));
2157
- const orchestrator = JSON.parse(readText("init/xinyun-ai-init/templates/orchestrator.template.json"));
2158
- const graph = JSON.parse(readText("init/xinyun-ai-init/templates/task-graph.template.json"));
2159
- const handoff = JSON.parse(readText("init/xinyun-ai-init/templates/handoff.template.json"));
2160
- const delivery = JSON.parse(readText("init/xinyun-ai-init/templates/final-delivery.template.json"));
2161
- const evidence = JSON.parse(readText("test-scenarios/v1.14.0-behavior-evidence.json"));
2162
- const ruleText = readText("init/xinyun-ai-init/rules/v1.14.0-agent-core.md");
2163
- const coreRules = readText("init/xinyun-ai-init/templates/core-rules.template.md");
2164
-
2165
- const pathKeys = ["profile", "capabilities", "takeoverGate", "orchestrator", "taskGraph", "handoffsDirectory", "finalDelivery"];
2166
- addCheck("v1.14 manifest/project-index registration", manifest.v114 && projectIndex.v114 && manifest.agentCore && projectIndex.agentCore && pathKeys.every((key) => manifest.agentCore[key] === projectIndex.agentCore[key] || key === "handoffsDirectory"), "v1.14 control-plane paths must be registered");
2167
- addCheck("v1.14 init-result registration", initResult.v114 && initResult.agentCore && initResult.agentCore.profilePath === manifest.agentCore.profile && initResult.v114.finalDeliveryPath === manifest.agentCore.finalDelivery, "init-result links v1.14 records");
2168
- addCheck("v1.14 agent profile", ["agentId", "name", "version", "projectIdentity", "serviceGoal", "configuredRoles", "supportedStacks", "supportedTools", "allowedOperations", "forbiddenOperations", "readyPrerequisites", "capabilityStatus"].every((field) => Object.prototype.hasOwnProperty.call(profile, field)) && profile.configuredRoles.length === 5 && profile.capabilityStatus === "manual-required", "agent profile contract is complete and conservative");
2169
- addCheck("v1.14 capability status", JSON.stringify(capabilities.aggregateStatusEnum) === JSON.stringify(["ready", "partial", "blocked", "manual-required"]) && capabilities.aggregateStatus === "manual-required" && capabilities.capabilities[0].required === true, "capability aggregation defaults to manual-required");
2170
- addCheck("v1.14 takeover gate", takeover.status === "blocked" && takeover.executionEligible === false && takeover.requiredGates.length >= 12 && takeover.blockedReasons.includes("required-role-session-not-created"), "takeover gate blocks without required evidence");
2171
- addCheck("v1.14 orchestrator and graph", orchestrator.orchestratorSessionId === null && orchestrator.responsibilities.length >= 8 && graph.acyclic === true && graph.taskStatusLabelMap.completed === "已完成", "orchestrator and task graph are independent and gated");
2172
- addCheck("v1.14 task status compatibility", taskIndex.taskStatusLabelMap.blocked === "阻塞" && taskIndex.taskStatusLabelMap["waiting-review"] === "待审查" && projectStatus.agentStatus === "manual-required" && projectStatus.takeoverGateStatus === "blocked", "machine statuses remain compatible with Chinese labels");
2173
- addCheck("v1.14 handoff and delivery", handoff.readBeforeExecution && handoff.readBeforeExecution.projectSnapshotHash === null && Array.isArray(handoff.changedFiles) && Array.isArray(delivery.blockedTasks) && delivery.status === "blocked", "handoff read/write and final delivery contracts are present");
2174
- addCheck("v1.14 session naming safety", readText("init/xinyun-ai-init/templates/role-session-binding.template.json").includes("项目名|角色|职责或工作流") && readText("init/xinyun-ai-init/templates/role-session-binding.template.json").includes("localSessionId") && ruleText.includes("providerSessionId") && ruleText.includes("local-degraded") && ruleText.includes("Cross-project"), "session naming keeps canonical provider identity and explicit local fallback");
2175
- const expectedIds = Array.from({ length: 20 }, (_, index) => 186 + index);
2176
- const scenarioText = readText("test-scenarios/v1.14.0-scenarios.md");
2177
- addCheck("v1.14 scenario catalog", expectedIds.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("beforeSnapshotHash") && scenarioText.includes("conflict"), "v1.14 scenarios 186-205 are catalogued");
2178
- addCheck("v1.14 behavior evidence local gate", evidence.version === "1.14.0" && evidence.evidenceType === "local-session" && evidence.executionMode === "local-degraded" && evidence.sessionIdentityMode === "local-degraded" && evidence.realAiSessionVerified === false && evidence.readyEligible === false && evidence.publishBlocked === false && typeof evidence.localSessionId === "string" && evidence.providerSessionId === null && JSON.stringify(evidence.scenarioRange) === JSON.stringify([186, 205]), "v1.14 local-degraded evidence is publishable but non-ready");
2179
- const v114EvidenceFields = ["scenarioId", "input", "expectedOutput", "actualOutput", "beforeSnapshotHash", "afterSnapshotHash", "changedFiles", "controlFilesChanged", "forbiddenOperations", "evidence", "sensitiveScan", "result", "recordHash", "recordedAt", "localSessionId"];
2180
- addCheck("v1.14 behavior evidence fields", JSON.stringify(evidence.scenarioRequiredFields) === JSON.stringify(v114EvidenceFields) && evidence.scenarios.length === 20 && evidence.scenarios.every((scenario, index) => v114EvidenceFields.every((field) => Object.prototype.hasOwnProperty.call(scenario, field)) && scenario.scenarioId === expectedIds[index] && scenario.expectedOutput && scenario.actualOutput === "local-degraded-verified" && scenario.sessionId === null && scenario.providerSessionId === null && scenario.localSessionId === evidence.localSessionId && scenario.result === "local-passed" && scenario.recordHash !== "not-recorded" && scenario.sensitiveScan && scenario.sensitiveScan.status === "pass" && scenario.sensitiveScan.matches.length === 0), "v1.14 behavior evidence has complete local auditable fields without fake provider IDs");
2181
- addCheck("v1.14 rule and core rule", ["Agent identity", "Takeover gate", "Orchestrator", "Shared facts", "Final delivery", "localSessionId", "local-degraded"].every((term) => ruleText.includes(term)) && coreRules.includes("v1.14.0 智能体核心能力"), "v1.14 rules are registered in the package guidance");
2182
- }
2183
-
2184
- function verifyV115Contracts() {
2185
- const requiredFiles = [
2186
- "init/xinyun-ai-init/rules/v1.15.0-session-binding.md",
2187
- "init/xinyun-ai-init/templates/session-binding.template.json",
2188
- "test-scenarios/v1.15.0-scenarios.md",
2189
- "test-scenarios/v1.15.0-behavior-evidence.json",
2190
- ];
2191
- requiredFiles.forEach(requireFile);
2192
- const manifest = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
2193
- const projectIndex = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
2194
- const initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
2195
- const binding = JSON.parse(readText("init/xinyun-ai-init/templates/session-binding.template.json"));
2196
- const evidence = JSON.parse(readText("test-scenarios/v1.15.0-behavior-evidence.json"));
2197
- const fields = ["sessionId", "sessionRefType", "sessionRef", "hostId", "provider", "projectRootHash", "workspaceScope", "repositoryScope", "workstream", "roleId", "taskId", "title", "cwd", "identityEvidence", "interactionEvidence", "bindingStatus", "bindingMode", "createdAt", "updatedAt"];
2198
- const categories = ["create-or-reuse", "send", "receive", "query-status", "recover", "close", "control-file-read-write"];
2199
- addCheck("v1.15 adapter-neutral registry", manifest.v115 && projectIndex.v115 && initResult.v115 && manifest.v115.sessionBindingTemplate === projectIndex.v115.sessionBindingTemplate && manifest.v115.sessionBindingTemplate === initResult.v115.sessionBindingTemplate && manifest.v115.canonicalControlPlaneId === "sessionId", "v1.15 registry paths and canonical control-plane ID are consistent");
2200
- addCheck("v1.15 session binding schema", fields.every((field) => Object.prototype.hasOwnProperty.call(binding, field)) && JSON.stringify(binding.requiredEvidenceCategories) === JSON.stringify(categories) && binding.bindingStatus === "pending" && binding.executionEligible === false, "v1.15 binding schema has all fields, seven evidence categories, and a non-ready default");
2201
- const ruleText = readText("init/xinyun-ai-init/rules/v1.15.0-session-binding.md");
2202
- addCheck("v1.15 session binding rule", ["adapter-neutral", "sessionRefType", "host-thread", "provider-session", "manual-reference", "local-session", "providerSessionId", "seven evidence"].every((term) => ruleText.includes(term)), "v1.15 adapter-neutral session binding rules are present");
2203
- const scenarioText = readText("test-scenarios/v1.15.0-scenarios.md");
2204
- const ids = Array.from({ length: 18 }, (_, index) => 206 + index);
2205
- addCheck("v1.15 scenario catalog", ids.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("跨项目") && scenarioText.includes("host-thread"), "v1.15 scenarios 206-223 are catalogued");
2206
- const evidenceOperations = new Set((evidence.interactionEvidence || []).map((record) => record.operation));
2207
- const plannedEvidence = evidence.evidenceType === "not-verified" && evidence.realAiSessionVerified === false && evidence.publishBlocked === true && evidence.scenarios.every((scenario) => scenario.actualOutput === "not-verified" && scenario.result === "not-verified");
2208
- const realHostEvidence = evidence.evidenceType === "real-session" && evidence.realAiSessionVerified === true && evidence.sessionRefType === "host-thread" && typeof evidence.sessionRef === "string" && evidence.readyEligible === true && categories.every((operation) => evidenceOperations.has(operation)) && evidence.scenarios.some((scenario) => scenario.scenarioId === 206 && scenario.result === "real-passed" && scenario.sessionRef === evidence.sessionRef) && evidence.scenarios.every((scenario) => scenario.result === "real-passed" || scenario.result === "real-negative-passed" || scenario.result === "contract-passed");
2209
- addCheck("v1.15 behavior evidence gate", evidence.version === "1.15.0" && JSON.stringify(evidence.scenarioRange) === JSON.stringify([206, 223]) && evidence.scenarios.length === 18 && evidence.scenarios.every((scenario, index) => scenario.scenarioId === 206 + index) && (plannedEvidence || realHostEvidence), "v1.15 behavior evidence is either honestly planned or backed by all seven real host-thread operation records");
2210
- }
2211
-
2212
- function verifyV116Contracts() {
2213
- const requiredFiles = [
2214
- "init/xinyun-ai-init/rules/v1.16.0-capability-efficiency.md",
2215
- "init/xinyun-ai-init/templates/skill-runtime-route.template.json",
2216
- "init/xinyun-ai-init/templates/skill-run-record.template.json",
2217
- "init/xinyun-ai-init/templates/codegraph-incremental-record.template.json",
2218
- "init/xinyun-ai-init/templates/local-query-index.template.json",
2219
- "init/xinyun-ai-init/templates/performance-metrics.template.json",
2220
- "test-scenarios/v1.16.0-scenarios.md",
2221
- "test-scenarios/v1.16.0-behavior-evidence.json",
2222
- "scripts/collect-v1.16-evidence.js",
2223
- ];
2224
- requiredFiles.forEach(requireFile);
2225
- const manifest = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
2226
- const projectIndex = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
2227
- const initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
2228
- const route = JSON.parse(readText("init/xinyun-ai-init/templates/skill-runtime-route.template.json"));
2229
- const run = JSON.parse(readText("init/xinyun-ai-init/templates/skill-run-record.template.json"));
2230
- const graph = JSON.parse(readText("init/xinyun-ai-init/templates/codegraph-incremental-record.template.json"));
2231
- const index = JSON.parse(readText("init/xinyun-ai-init/templates/local-query-index.template.json"));
2232
- const metrics = JSON.parse(readText("init/xinyun-ai-init/templates/performance-metrics.template.json"));
2233
- const evidence = JSON.parse(readText("test-scenarios/v1.16.0-behavior-evidence.json"));
2234
- const scenarioText = readText("test-scenarios/v1.16.0-scenarios.md");
2235
- const ruleText = readText("init/xinyun-ai-init/rules/v1.16.0-capability-efficiency.md");
2236
- const expectedIds = Array.from({ length: 15 }, (_, index) => index + 301);
2237
- addCheck("v1.16 registry", manifest.v116 && projectIndex.v116 && initResult.v116 && manifest.v116.skillRoute === "xinyun-ai/skills/runtime-routes.json" && projectIndex.v116.skillRoute === manifest.v116.skillRoute && initResult.v116.skillRoutePath === manifest.v116.skillRoute, "v1.16 runtime paths are consistent");
2238
- addCheck("v1.16 route and run schemas", ["selected", "rejected", "fallback", "blocked", "selectionOrder"].every((field) => Object.prototype.hasOwnProperty.call(route, field)) && ["skillRunId", "skillId", "taskId", "usedTools", "unusedTools", "unverifiedScope"].every((field) => Object.prototype.hasOwnProperty.call(run, field)), "Skill routing and execution records are complete");
2239
- addCheck("v1.16 CodeGraph and query index schemas", ["changedFiles", "unchangedFiles", "failedFiles", "oldHealthyIndexPreserved"].every((field) => Object.prototype.hasOwnProperty.call(graph, field)) && ["sourceHash", "builtAt", "indexVersion", "coverage", "stale", "queryBudget"].every((field) => Object.prototype.hasOwnProperty.call(index, field)), "Incremental CodeGraph and derived query index records are complete");
2240
- addCheck("v1.16 efficiency schema", metrics.fixedMaterializationTargetMs === 5000 && metrics.stageRequiredFields.includes("cacheHit") && Object.prototype.hasOwnProperty.call(metrics.metrics, "controlPlaneReads"), "Efficiency metrics include repeatable stages and the 5-second target");
2241
- addCheck("v1.16 rule", ["Runtime Skill routing", "Incremental CodeGraph", "local query index", "SQLite is optional", "providerSessionId", "partial", "blocked"].every((term) => ruleText.includes(term)), "v1.16 capability rules are present");
2242
- addCheck("v1.16 scenario catalog", expectedIds.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("three batches"), "v1.16 scenarios 301-315 are catalogued");
2243
- const expectedRealBehavior = ["skill-route", "codegraph-cache", "incremental-update", "query-index", "efficiency-metrics"];
2244
- const scenarioResultsValid = evidence.scenarios.every((scenario, index) => scenario.scenarioId === expectedIds[index] && (scenario.result === "contract-passed" || scenario.result === "real-passed") && (scenario.result !== "real-passed" || scenario.sessionRef === evidence.sessionRef));
2245
- const plannedEvidence = evidence.evidenceType === "contract-regression" && evidence.realAiSessionVerified === false && evidence.publishBlocked === true && evidence.readyEligible === false;
2246
- const realHostEvidence = evidence.evidenceType === "real-session" && evidence.executionMode === "real-host" && evidence.realAiSessionVerified === true && evidence.sessionRefType === "host-thread" && typeof evidence.sessionRef === "string" && evidence.readyEligible === true && evidence.publishBlocked === false && Array.isArray(evidence.verifiedRealBehavior) && expectedRealBehavior.every((item) => evidence.verifiedRealBehavior.includes(item)) && evidence.sensitiveScan && evidence.sensitiveScan.status === "pass" && evidence.sensitiveScan.matches.length === 0;
2247
- addCheck("v1.16 behavior evidence", evidence.version === "1.16.0" && JSON.stringify(evidence.scenarioRange) === JSON.stringify([301, 315]) && evidence.scenarios.length === 15 && scenarioResultsValid && (plannedEvidence || realHostEvidence), "v1.16 behavior evidence is either honestly planned or backed by the recorded real host probe");
2248
- }
2249
-
2250
- function main() {
2251
- requireFile("bin/xinyun-ai-init.js");
2252
- requireFile("init/xinyun-ai-init/README.md");
2253
- requireFile("init/xinyun-ai-init/version.json");
2254
-
2255
- verifyPackageFiles();
2256
- verifyCliBoundary();
2257
- verifyInitRules();
2258
- verifyFrameworkRules();
2259
- verifyTeamTemplates();
2260
- verifyV16Contracts();
2261
- verifyV17Contracts();
2262
- verifyV171Contracts();
2263
- verifyV172Contracts();
2264
- verifyV173Contracts();
2265
- verifyV18Contracts();
2266
- verifyV19Contracts();
2267
- verifyV19SessionReuseText();
2268
- verifyV110Contracts();
2269
- verifyV112Contracts();
2270
- verifyV1121Contracts();
2271
- verifyV113Contracts();
2272
- verifyV114Contracts();
2273
- verifyV115Contracts();
2274
- verifyV116Contracts();
2275
- verifyTestScenarios();
2276
- verifyJsonAndMarkdown();
2277
-
2278
- const failed = checks.filter((check) => !check.ok);
2279
-
2280
- for (const check of checks) {
2281
- const prefix = check.ok ? "[PASS]" : "[FAIL]";
2282
- console.log(`${prefix} ${check.name}`);
2283
- if (!check.ok && check.detail) {
2284
- console.log(` ${check.detail}`);
2285
- }
2286
- }
2287
-
2288
- console.log("");
2289
- console.log(`[xinyun-ai-init verify] ${checks.length - failed.length}/${checks.length} checks passed.`);
2290
-
2291
- if (failed.length > 0) {
2292
- process.exit(1);
2293
- }
2294
- }
2295
-
2296
- main();
2297
-