@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,1287 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require("fs");
4
- const os = require("os");
5
- const path = require("path");
6
- const { spawnSync } = require("child_process");
7
-
8
- const v2Root = path.resolve(__dirname, "..");
9
- if (require(path.join(v2Root, "package.json")).version.startsWith("2.")) {
10
- const targetScript = process.argv.includes("--tarball") ? "verify-v2-tarball.js" : "verify-v2-package.js";
11
- const result = spawnSync(process.execPath, [path.join(__dirname, targetScript), ...process.argv.slice(2)], { stdio: "inherit" });
12
- process.exit(typeof result.status === "number" ? result.status : 1);
13
- }
14
-
15
- const VERSION = "1.16.0";
16
- const checks = [];
17
-
18
- function parseArgs(argv) {
19
- const options = { sourceRoot: process.cwd(), tarball: null, json: false, help: false };
20
-
21
- for (let index = 0; index < argv.length; index += 1) {
22
- const arg = argv[index];
23
- if (arg === "--source-root") {
24
- const value = argv[index + 1];
25
- if (!value) throw Object.assign(new Error("--source-root requires a path"), { exitCode: 2 });
26
- options.sourceRoot = value;
27
- index += 1;
28
- } else if (arg === "--tarball") {
29
- const value = argv[index + 1];
30
- if (!value) throw Object.assign(new Error("--tarball requires a path"), { exitCode: 2 });
31
- options.tarball = value;
32
- index += 1;
33
- } else if (arg === "--json") {
34
- options.json = true;
35
- } else if (arg === "--help" || arg === "-h") {
36
- options.help = true;
37
- } else {
38
- throw Object.assign(new Error(`Unknown argument: ${arg}`), { exitCode: 2 });
39
- }
40
- }
41
-
42
- options.sourceRoot = path.resolve(options.sourceRoot);
43
- if (options.tarball) options.tarball = path.resolve(options.tarball);
44
- return options;
45
- }
46
-
47
- function addCheck(target, checkId, category, status, pathValue, field, expected, actual, message, suggestion, severity = "required") {
48
- checks.push({
49
- checkId,
50
- target,
51
- category,
52
- status,
53
- severity,
54
- path: pathValue || null,
55
- field: field || null,
56
- expected: expected === undefined ? null : expected,
57
- actual: actual === undefined ? null : actual,
58
- message,
59
- suggestion: suggestion || null,
60
- });
61
- }
62
-
63
- function readText(root, relativePath) {
64
- return fs.readFileSync(path.join(root, relativePath), "utf8").replace(/^\uFEFF/, "");
65
- }
66
-
67
- function readJson(root, relativePath) {
68
- return JSON.parse(readText(root, relativePath));
69
- }
70
-
71
- function existsPath(root, relativePath) {
72
- return fs.existsSync(path.join(root, relativePath));
73
- }
74
-
75
- function existsFile(root, relativePath) {
76
- return existsPath(root, relativePath) && fs.statSync(path.join(root, relativePath)).isFile();
77
- }
78
-
79
- function requireFile(root, target, relativePath) {
80
- const ok = existsFile(root, relativePath);
81
- addCheck(
82
- target,
83
- "path.reference",
84
- "path",
85
- ok ? "pass" : "fail",
86
- relativePath,
87
- null,
88
- "file exists",
89
- ok ? "file exists" : "missing",
90
- ok ? "Required file exists." : "Required file is missing.",
91
- ok ? null : "Add the file or update the rule/package reference."
92
- );
93
- }
94
-
95
- function requireIncludes(root, target, relativePath, snippets, checkId = "content.required") {
96
- let content;
97
- try {
98
- content = readText(root, relativePath);
99
- } catch (error) {
100
- addCheck(target, checkId, "content", "fail", relativePath, null, "readable text", error.message, "File could not be read.", "Restore the file or fix permissions.");
101
- return;
102
- }
103
-
104
- for (const snippet of snippets) {
105
- const expectedSnippet = snippet === "当前规则版本:`1.9.0`" ? `当前规则版本:\`${VERSION}\`` : snippet;
106
- const ok = content.includes(expectedSnippet);
107
- addCheck(
108
- target,
109
- checkId,
110
- "content",
111
- ok ? "pass" : "fail",
112
- relativePath,
113
- null,
114
- expectedSnippet,
115
- ok ? expectedSnippet : "not found",
116
- ok ? `Found required content: ${snippet}` : `Missing required content: ${snippet}`,
117
- ok ? null : "Synchronize README, templates, and rule files."
118
- );
119
- }
120
- }
121
-
122
- const v19SessionReuseFiles = [
123
- "init/xinyun-ai-init/README.md",
124
- "init/xinyun-ai-init/templates/AGENTS.template.md",
125
- "init/xinyun-ai-init/templates/core-rules.template.md",
126
- "init/xinyun-ai-init/templates/project-guide.template.md",
127
- "init/xinyun-ai-init/templates/project-check.template.md",
128
- "init/xinyun-ai-init/templates/role-execution.template.md",
129
- "init/xinyun-ai-init/rules/init-rules.md",
130
- "init/xinyun-ai-init/rules/upgrade-rules.md",
131
- "init/xinyun-ai-init/rules/session-workbench.md",
132
- ];
133
-
134
- const v19SessionKeyFields = [
135
- "projectRootHash",
136
- "workspaceScope",
137
- "repositoryScopeHash",
138
- "workstream",
139
- "taskId",
140
- "roleId",
141
- "provider",
142
- "targetVersion",
143
- ];
144
-
145
- function validateV19SessionReuseText(root, target) {
146
- const legacyPatterns = [
147
- /\btaskId\s*\+\s*roleId\s*\+\s*provider\s*\+\s*targetVersion\b/,
148
- /JCS-SHA-256\s*\(\s*taskId\s*,\s*roleId\s*,\s*provider\s*,\s*targetVersion\s*\)/,
149
- /(?:roleSessionIdempotency|sessionIdempotencyKey|legacyCreationIndexFields)[^\n]{0,300}\{\s*taskId\s*,\s*roleId\s*,\s*provider\s*,\s*targetVersion\s*\}/,
150
- ];
151
- const allowedLegacyMarkers = [
152
- /legacy/i,
153
- /compatib/i,
154
- /兼容/,
155
- /不得参与候选选择/,
156
- /不参与候选选择/,
157
- /绝不参与/,
158
- /never used for candidate selection/i,
159
- /only.*creation/i,
160
- /只作/,
161
- /仅作/,
162
- ];
163
-
164
- for (const relativePath of v19SessionReuseFiles) {
165
- let content;
166
- try {
167
- content = readText(root, relativePath);
168
- } catch (error) {
169
- addCheck(target, "v1.9.session-reuse-text", "content", "error", relativePath, null, "readable text", error.message, "Could not scan session reuse text.", "Restore the file or fix permissions.");
170
- continue;
171
- }
172
- const hits = [];
173
- for (const [index, line] of content.split(/\r?\n/).entries()) {
174
- if (!legacyPatterns.some((pattern) => pattern.test(line))) continue;
175
- hits.push({ line: index + 1, allowed: allowedLegacyMarkers.some((marker) => marker.test(line)) });
176
- }
177
- const unauthorized = hits.filter((hit) => !hit.allowed);
178
- addCheck(target, "v1.9.session-reuse-text", "content", unauthorized.length === 0 ? "pass" : "fail", relativePath, null, "legacy tuple only in compatibility context", unauthorized.length === 0 ? "pass" : unauthorized.map((hit) => `L${hit.line}`).join(", "), unauthorized.length === 0 ? "Old tuple is compatibility-only." : "Old tuple is used as an executable reuse contract.", "Use the full v1.9 project-isolated key and keep legacy fields compatibility-only.");
179
- addCheck(target, "v1.9.session-reuse-full-key", "content", v19SessionKeyFields.every((field) => content.includes(field)) && content.includes("RFC8785-JCS-SHA-256") ? "pass" : "fail", relativePath, null, "eight fields and RFC8785-JCS-SHA-256", "scanned", "Full v1.9 session reuse key is present.", "Add the full v1.9 reuse contract.");
180
- }
181
- }
182
-
183
- function validateVersion(root, target) {
184
- const packageJson = readJson(root, "package.json");
185
- const versionJson = readJson(root, "init/xinyun-ai-init/version.json");
186
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
187
- const scripts = packageJson.scripts || {};
188
-
189
- const pairs = [
190
- ["package.json", "version", packageJson.version],
191
- ["init/xinyun-ai-init/version.json", "version", versionJson.version],
192
- ["init/xinyun-ai-init/templates/manifest.template.json", "xinyunAiVersion", manifest.xinyunAiVersion],
193
- ];
194
-
195
- for (const [file, field, actual] of pairs) {
196
- addCheck(target, "version.package", "version", actual === VERSION ? "pass" : "fail", file, field, VERSION, actual, "Version consistency checked.", "Update all version metadata to the release version.");
197
- }
198
-
199
- addCheck(target, "script.entry", "script", scripts["verify:init"] === "node ./scripts/verify-init-package.js" ? "pass" : "fail", "package.json", "scripts.verify:init", "node ./scripts/verify-init-package.js", scripts["verify:init"], "verify:init script entry checked.", "Restore verify:init script.");
200
- addCheck(target, "script.entry", "script", scripts["verify:rules"] === "node ./scripts/verify-rules-package.js" ? "pass" : "fail", "package.json", "scripts.verify:rules", "node ./scripts/verify-rules-package.js", scripts["verify:rules"], "verify:rules script entry checked.", "Add verify:rules script.");
201
- addCheck(target, "script.entry", "script", scripts["evidence:v1.10"] === "node ./scripts/collect-v1.10-evidence.js" ? "pass" : "fail", "package.json", "scripts.evidence:v1.10", "node ./scripts/collect-v1.10-evidence.js", scripts["evidence:v1.10"], "v1.10 evidence collector entry checked.", "Add the bounded real-session evidence collector.");
202
- }
203
-
204
- function validatePackageFiles(root, target, isTarball) {
205
- const packageJson = readJson(root, "package.json");
206
- const requiredEntries = ["bin/", "init/", "scripts/", "test-scenarios/", "README.md"];
207
- for (const entry of requiredEntries) {
208
- const ok = Array.isArray(packageJson.files) && packageJson.files.includes(entry);
209
- addCheck(target, "package.files", "package", ok ? "pass" : "fail", "package.json", "files", entry, packageJson.files, "Package files whitelist checked.", "Add the missing package files entry.");
210
- }
211
-
212
- const requiredFiles = [
213
- "README.md",
214
- "bin/xinyun-ai-init.js",
215
- "scripts/verify-init-package.js",
216
- "scripts/verify-rules-package.js",
217
- "scripts/verify-rules-tarball-security.js",
218
- "test-scenarios/README.md",
219
- "test-scenarios/review-template.md",
220
- "test-scenarios/scenarios.md",
221
- "test-scenarios/v1.7.1-scenarios.md",
222
- "test-scenarios/v1.7.2-scenarios.md",
223
- "test-scenarios/v1.7.3-scenarios.md",
224
- "init/xinyun-ai-init/README.md",
225
- "init/xinyun-ai-init/rules/frameworks/README.md",
226
- "init/xinyun-ai-init/rules/frameworks/backend/php/thinkphp.md",
227
- "init/xinyun-ai-init/templates/AGENTS.template.md",
228
- "init/xinyun-ai-init/templates/core-rules.template.md",
229
- "init/xinyun-ai-init/templates/current-task.template.md",
230
- "init/xinyun-ai-init/templates/project-check.template.md",
231
- "init/xinyun-ai-init/templates/project-guide.template.md",
232
- "init/xinyun-ai-init/templates/project-index.template.json",
233
- "init/xinyun-ai-init/templates/manifest.template.json",
234
- "init/xinyun-ai-init/templates/framework-profile.template.md",
235
- "init/xinyun-ai-init/templates/framework-profile.template.json",
236
- "init/xinyun-ai-init/templates/html-migration-scope.template.md",
237
- "init/xinyun-ai-init/templates/html-migration-compatibility-matrix.template.md",
238
- "init/xinyun-ai-init/templates/html-migration-route-map.template.md",
239
- "init/xinyun-ai-init/templates/html-migration-asset-map.template.md",
240
- "init/xinyun-ai-init/templates/html-migration-pilot-plan.template.md",
241
- "init/xinyun-ai-init/templates/html-migration-open-issues.template.md",
242
- "init/xinyun-ai-init/templates/html-migration-record.template.json",
243
- "init/xinyun-ai-init/templates/task-index.template.json",
244
- "init/xinyun-ai-init/templates/task-main.template.md",
245
- "init/xinyun-ai-init/templates/role-subtask.template.md",
246
- "init/xinyun-ai-init/templates/archive-transaction.template.json",
247
- "init/xinyun-ai-init/templates/role-execution.template.md",
248
- "init/xinyun-ai-init/templates/role-session-binding.template.json",
249
- "init/xinyun-ai-init/templates/provider-session-binding.template.json",
250
- "init/xinyun-ai-init/templates/manual-session-binding.template.json",
251
- "init/xinyun-ai-init/templates/coordination-project-facts.template.json",
252
- "init/xinyun-ai-init/templates/coordination-change-ledger.template.json",
253
- "init/xinyun-ai-init/templates/coordination-contract-snapshot.template.json",
254
- "init/xinyun-ai-init/templates/coordination-conflict-record.template.json",
255
- "init/xinyun-ai-init/templates/coordination-transaction.template.json",
256
- "init/xinyun-ai-init/templates/skills-registry.template.json",
257
- "init/xinyun-ai-init/templates/skills-assignments.template.json",
258
- "init/xinyun-ai-init/templates/frontend-audit.template.json",
259
- "init/xinyun-ai-init/templates/temporary-session.template.json",
260
- "init/xinyun-ai-init/rules/coordination.md",
261
- "init/xinyun-ai-init/rules/skills.md",
262
- "init/xinyun-ai-init/rules/frontend-audit.md",
263
- "init/xinyun-ai-init/rules/temporary-sessions.md",
264
- "test-scenarios/v1.8.0-scenarios.md",
265
- "test-scenarios/v1.9.0-scenarios.md",
266
- "test-scenarios/v1.9.0-behavior-evidence.json",
267
- "test-scenarios/v1.10.0-scenarios.md",
268
- "test-scenarios/v1.10.0-behavior-evidence.json",
269
- "test-scenarios/v1.12.0-scenarios.md",
270
- "test-scenarios/v1.12.0-behavior-evidence.json",
271
- "init/xinyun-ai-init/templates/project-identity.template.json",
272
- "init/xinyun-ai-init/templates/session-candidates.template.json",
273
- "init/xinyun-ai-init/templates/technical-landscape.template.json",
274
- "init/xinyun-ai-init/templates/requirement-packet.template.json",
275
- "init/xinyun-ai-init/templates/technical-impact-packet.template.json",
276
- "init/xinyun-ai-init/templates/database-authorization.template.json",
277
- "init/xinyun-ai-init/templates/agent-profile.template.json",
278
- "init/xinyun-ai-init/templates/agent-capabilities.template.json",
279
- "init/xinyun-ai-init/templates/takeover-gate.template.json",
280
- "init/xinyun-ai-init/templates/orchestrator.template.json",
281
- "init/xinyun-ai-init/templates/task-graph.template.json",
282
- "init/xinyun-ai-init/templates/handoff.template.json",
283
- "init/xinyun-ai-init/templates/final-delivery.template.json",
284
- "init/xinyun-ai-init/templates/host-preflight.template.json",
285
- "init/xinyun-ai-init/templates/initialization-recovery.template.json",
286
- "init/xinyun-ai-init/templates/manual-session-binding.template.json",
287
- "init/xinyun-ai-init/templates/shared-project-snapshot.template.json",
288
- "init/xinyun-ai-init/templates/initialization-timing.template.json",
289
- "init/xinyun-ai-init/rules/v1.12.0-recovery.md",
290
- "init/xinyun-ai-init/rules/v1.13.0-host-adapter.md",
291
- "init/xinyun-ai-init/templates/provider-adapter.template.json",
292
- "init/xinyun-ai-init/templates/manual-session-recovery.template.json",
293
- "init/xinyun-ai-init/templates/initialization-change-report.template.json",
294
- "init/xinyun-ai-init/templates/role-session-binding.template.json",
295
- "init/xinyun-ai-init/templates/provider-session-binding.template.json",
296
- "init/xinyun-ai-init/templates/task-index.template.json",
297
- "init/xinyun-ai-init/templates/team/assignments.json",
298
- "test-scenarios/v1.13.0-scenarios.md",
299
- "test-scenarios/v1.13.0-behavior-evidence.json",
300
- "test-scenarios/v1.14.0-scenarios.md",
301
- "test-scenarios/v1.14.0-behavior-evidence.json",
302
- "init/xinyun-ai-init/rules/v1.14.0-agent-core.md",
303
- "init/xinyun-ai-init/templates/agent-profile.template.json",
304
- "init/xinyun-ai-init/templates/agent-capabilities.template.json",
305
- "init/xinyun-ai-init/templates/takeover-gate.template.json",
306
- "init/xinyun-ai-init/templates/orchestrator.template.json",
307
- "init/xinyun-ai-init/templates/task-graph.template.json",
308
- "init/xinyun-ai-init/templates/handoff.template.json",
309
- "init/xinyun-ai-init/templates/final-delivery.template.json",
310
- ];
311
-
312
- for (const file of requiredFiles) requireFile(root, target, file);
313
-
314
- if (isTarball) {
315
- const sourceOnly = "version-plans/releases/v1.10.0.md";
316
- addCheck(target, "package.source-only", "package", !existsPath(root, sourceOnly) ? "pass" : "warn", sourceOnly, null, "not required in tarball", existsPath(root, sourceOnly) ? "present" : "not present", "source-only version-plans is not required in tarball.", "No action required unless package policy changes.", "optional");
317
- }
318
- }
319
-
320
- function validateTarballSecurityContract(root, target) {
321
- requireIncludes(root, target, "scripts/verify-rules-package.js", [
322
- "validateTarEntryName",
323
- "validateTarEntryTypes",
324
- "verifyExtractedTree",
325
- "path traversal",
326
- "symbolic link",
327
- "hard link",
328
- ], "tarball.security");
329
- requireIncludes(root, target, "scripts/verify-rules-tarball-security.js", [
330
- "traversal",
331
- "absolute",
332
- "backslash-traversal",
333
- "symlink",
334
- "hardlink",
335
- ], "tarball.security");
336
- }
337
-
338
- function validateRegistries(root, target) {
339
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
340
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
341
- const capabilities = manifest.capabilities || {};
342
-
343
- for (const flag of [
344
- "rulePackageConsistencyCheck",
345
- "technologyStackProfile",
346
- "thinkphpDeepProfile",
347
- "htmlToClientMigrationPreparation",
348
- "namedInitializationTaskTree",
349
- "taskArchiveTransactions",
350
- "codeGraphRequiredInitialization",
351
- "roleExecutionVisibility",
352
- "codexRoleSessionOrchestration",
353
- ]) {
354
- addCheck(target, "registry.manifest", "manifest", capabilities[flag] === true ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", `capabilities.${flag}`, true, capabilities[flag], "Manifest capability registered.", "Register the missing capability.");
355
- }
356
-
357
- const manifestPaths = {
358
- "frameworkProfile.directory": manifest.frameworkProfile && manifest.frameworkProfile.directory,
359
- "frameworkProfile.markdown": manifest.frameworkProfile && manifest.frameworkProfile.markdown,
360
- "frameworkProfile.json": manifest.frameworkProfile && manifest.frameworkProfile.json,
361
- "htmlMigration.directory": manifest.htmlMigration && manifest.htmlMigration.directory,
362
- "htmlMigration.scope": manifest.htmlMigration && manifest.htmlMigration.scope,
363
- "htmlMigration.compatibilityMatrix": manifest.htmlMigration && manifest.htmlMigration.compatibilityMatrix,
364
- "htmlMigration.routeMap": manifest.htmlMigration && manifest.htmlMigration.routeMap,
365
- "htmlMigration.assetMap": manifest.htmlMigration && manifest.htmlMigration.assetMap,
366
- "htmlMigration.pilotPlan": manifest.htmlMigration && manifest.htmlMigration.pilotPlan,
367
- "htmlMigration.openIssues": manifest.htmlMigration && manifest.htmlMigration.openIssues,
368
- "htmlMigration.recordJson": manifest.htmlMigration && manifest.htmlMigration.recordJson,
369
- };
370
- const expectedPaths = {
371
- "frameworkProfile.directory": "xinyun-ai/frameworks/",
372
- "frameworkProfile.markdown": "xinyun-ai/frameworks/framework-profile.md",
373
- "frameworkProfile.json": "xinyun-ai/frameworks/framework-profile.json",
374
- "htmlMigration.directory": "xinyun-ai/migrations/html-to-client/",
375
- "htmlMigration.scope": "xinyun-ai/migrations/html-to-client/migration-scope.md",
376
- "htmlMigration.compatibilityMatrix": "xinyun-ai/migrations/html-to-client/compatibility-matrix.md",
377
- "htmlMigration.routeMap": "xinyun-ai/migrations/html-to-client/route-map.md",
378
- "htmlMigration.assetMap": "xinyun-ai/migrations/html-to-client/asset-map.md",
379
- "htmlMigration.pilotPlan": "xinyun-ai/migrations/html-to-client/pilot-plan.md",
380
- "htmlMigration.openIssues": "xinyun-ai/migrations/html-to-client/open-issues.md",
381
- "htmlMigration.recordJson": "xinyun-ai/migrations/html-to-client/migration-record.json",
382
- };
383
-
384
- for (const [field, expected] of Object.entries(expectedPaths)) {
385
- addCheck(target, "registry.manifest", "manifest", manifestPaths[field] === expected ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", field, expected, manifestPaths[field], "Manifest path registration checked.", "Register the expected path.");
386
- }
387
-
388
- addCheck(target, "registry.project-index", "project-index", projectIndex.frameworkProfile && projectIndex.frameworkProfile.enabled === true ? "pass" : "fail", "init/xinyun-ai-init/templates/project-index.template.json", "frameworkProfile.enabled", true, projectIndex.frameworkProfile && projectIndex.frameworkProfile.enabled, "Project-index framework profile registered.", "Register frameworkProfile.");
389
- addCheck(target, "registry.project-index", "project-index", projectIndex.htmlMigration && projectIndex.htmlMigration.enabled === true ? "pass" : "fail", "init/xinyun-ai-init/templates/project-index.template.json", "htmlMigration.enabled", true, projectIndex.htmlMigration && projectIndex.htmlMigration.enabled, "Project-index HTML migration registered.", "Register htmlMigration.");
390
- addCheck(target, "registry.manifest", "manifest", manifest.taskTree && manifest.taskTree.enabled === true ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "taskTree.enabled", true, manifest.taskTree && manifest.taskTree.enabled, "Manifest task tree registered.", "Register taskTree.");
391
- addCheck(target, "registry.project-index", "project-index", projectIndex.taskTree && projectIndex.taskTree.enabled === true ? "pass" : "fail", "init/xinyun-ai-init/templates/project-index.template.json", "taskTree.enabled", true, projectIndex.taskTree && projectIndex.taskTree.enabled, "Project-index task tree registered.", "Register taskTree.");
392
- addCheck(target, "registry.manifest", "manifest", manifest.codeGraphRequired && manifest.codeGraphRequired.required === true ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "codeGraphRequired.required", true, manifest.codeGraphRequired && manifest.codeGraphRequired.required, "Manifest CodeGraph required record registered.", "Register codeGraphRequired.");
393
- addCheck(target, "registry.project-index", "project-index", projectIndex.codeGraphRequired && projectIndex.codeGraphRequired.required === true ? "pass" : "fail", "init/xinyun-ai-init/templates/project-index.template.json", "codeGraphRequired.required", true, projectIndex.codeGraphRequired && projectIndex.codeGraphRequired.required, "Project-index CodeGraph required record registered.", "Register codeGraphRequired.");
394
-
395
- const v171TaskingPaths = {
396
- "tasking.taskIndex": manifest.tasking && manifest.tasking.taskIndex,
397
- "tasking.archiveDirectory": manifest.tasking && manifest.tasking.archiveDirectory,
398
- "tasking.archiveTransactionsDirectory": manifest.tasking && manifest.tasking.archiveTransactionsDirectory,
399
- "tasking.archiveTempDirectory": manifest.tasking && manifest.tasking.archiveTempDirectory,
400
- "tasking.roleExecutionDirectory": manifest.tasking && manifest.tasking.roleExecutionDirectory,
401
- };
402
- const v171ExpectedPaths = {
403
- "tasking.taskIndex": "xinyun-ai/tasks/task-index.json",
404
- "tasking.archiveDirectory": "xinyun-ai/tasks/archive/",
405
- "tasking.archiveTransactionsDirectory": "xinyun-ai/tasks/.archive-transactions/",
406
- "tasking.archiveTempDirectory": "xinyun-ai/tasks/.archive-tmp/",
407
- "tasking.roleExecutionDirectory": "xinyun-ai/tasks/role-execution/",
408
- };
409
- for (const [field, expected] of Object.entries(v171ExpectedPaths)) {
410
- addCheck(target, "registry.manifest", "manifest", v171TaskingPaths[field] === expected ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", field, expected, v171TaskingPaths[field], "Manifest v1.7.1 tasking path checked.", "Register v1.7.1 tasking path.");
411
- }
412
- addCheck(target, "registry.manifest", "manifest", manifest.taskTree && manifest.taskTree.roleExecutionPathPattern === "xinyun-ai/tasks/role-execution/<roleTaskId>.md" ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "taskTree.roleExecutionPathPattern", "xinyun-ai/tasks/role-execution/<roleTaskId>.md", manifest.taskTree && manifest.taskTree.roleExecutionPathPattern, "Manifest role execution path checked.", "Register the role execution path.");
413
- addCheck(target, "registry.project-index", "project-index", projectIndex.taskTree && projectIndex.taskTree.roleExecutionPathPattern === "xinyun-ai/tasks/role-execution/<roleTaskId>.md" ? "pass" : "fail", "init/xinyun-ai-init/templates/project-index.template.json", "taskTree.roleExecutionPathPattern", "xinyun-ai/tasks/role-execution/<roleTaskId>.md", projectIndex.taskTree && projectIndex.taskTree.roleExecutionPathPattern, "Project-index role execution path checked.", "Register the role execution path.");
414
- addCheck(target, "registry.manifest", "manifest", manifest.roleSessions && manifest.roleSessions.bindings === "xinyun-ai/sessions/role-session-bindings.json" ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "roleSessions.bindings", "xinyun-ai/sessions/role-session-bindings.json", manifest.roleSessions && manifest.roleSessions.bindings, "Manifest role session bindings checked.", "Register roleSessions.bindings.");
415
- addCheck(target, "registry.project-index", "project-index", projectIndex.roleSessions && projectIndex.roleSessions.bindings === "xinyun-ai/sessions/role-session-bindings.json" ? "pass" : "fail", "init/xinyun-ai-init/templates/project-index.template.json", "roleSessions.bindings", "xinyun-ai/sessions/role-session-bindings.json", projectIndex.roleSessions && projectIndex.roleSessions.bindings, "Project-index role session bindings checked.", "Register roleSessions.bindings.");
416
- addCheck(target, "registry.manifest", "manifest", manifest.roleSessions && manifest.roleSessions.provider === "codex" ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "roleSessions.provider", "codex", manifest.roleSessions && manifest.roleSessions.provider, "Manifest role session provider checked.", "Register roleSessions.provider.");
417
- }
418
-
419
- function validateV17Content(root, target) {
420
- const common = [
421
- "verify:rules",
422
- "--source-root",
423
- "--tarball",
424
- "--json",
425
- "source-only version-plans",
426
- "frameworkStatus=confirmed/inferred/not-found/unknown/detected-unsupported",
427
- "moduleStatus=loaded/not-loaded",
428
- "activation=loaded/not-loaded",
429
- "v1.7 深化预算:5 层目录、80 个关键文件、100 条证据",
430
- "framework-profile.md",
431
- "framework-profile.json",
432
- "decision=direct-map/rewrite-required/backend-required/unsupported/pending/unknown",
433
- "status=planned/assessing/partial/blocked/paused/completed",
434
- "coverage=full/partial/unknown",
435
- "scope/unverifiedScope",
436
- "pauseReason=out-of-scope",
437
- ];
438
- requireIncludes(root, target, "init/xinyun-ai-init/README.md", ["当前规则版本:`1.9.0`", ...common]);
439
- requireIncludes(root, target, "init/xinyun-ai-init/templates/core-rules.template.md", common);
440
- requireIncludes(root, target, "init/xinyun-ai-init/templates/AGENTS.template.md", ["v1.7 规则包一致性、技术栈 profile 与 HTML 迁移准备", "`verify:rules` 只读", "ThinkPHP 不得误套其他项目", ...common.slice(5)]);
441
- requireIncludes(root, target, "init/xinyun-ai-init/templates/current-task.template.md", ["verify:rules.status", "language", "runtime", "platform", "framework", ...common.slice(5)]);
442
- requireIncludes(root, target, "init/xinyun-ai-init/templates/project-guide.template.md", ["verify:rules", "language / runtime / platform / framework", "migration-record.json", ...common.slice(5)]);
443
- requireIncludes(root, target, "init/xinyun-ai-init/templates/project-check.template.md", ["`npm run verify:rules`", "source-only version-plans", "migration-record.json", ...common.slice(5)]);
444
- requireIncludes(root, target, "init/xinyun-ai-init/rules/init-rules.md", ["v1.7 初始化补齐", "xinyun-ai/frameworks/", "xinyun-ai/migrations/html-to-client/", "`verify:rules` 为只读校验"]);
445
- requireIncludes(root, target, "init/xinyun-ai-init/rules/upgrade-rules.md", ["v1.7 规则包升级检查", "test-scenarios/v1.7.1-scenarios.md", "source-only version-plans", "frameworkProfile", "htmlMigration"]);
446
- requireIncludes(root, target, "init/xinyun-ai-init/rules/directory-self-completion.md", ["v1.7 按需目录补齐", "framework-profile.json", "migration-record.json", "首次极速初始化不强制创建上述目录"]);
447
- requireIncludes(root, target, "init/xinyun-ai-init/rules/session-workbench.md", ["v1.7 任务单补充字段", "verifyRulesStatus", "migrationStatus", "HTML 迁移只允许评估和单页面 / 区块试点计划"]);
448
- requireIncludes(root, target, "init/xinyun-ai-init/rules/frameworks/README.md", ["v1.7 技术栈 profile", "coverage=partial", ...common.slice(5, 10)]);
449
- requireIncludes(root, target, "init/xinyun-ai-init/rules/frameworks/backend/php/thinkphp.md", ["v1.7 ThinkPHP 深化模块", "frameworkStatus=confirmed", "moduleStatus=loaded", "Controller", "Request/Validate", "Service", "Model/ORM", "Middleware", "队列"]);
450
- requireIncludes(root, target, "test-scenarios/scenarios.md", ["当前必测场景为 1-133", "当前观察场景为 106 和 119", "## 55. verify:rules 正常通过", "## 69. verify:rules JSON schema 和重复执行"]);
451
- requireIncludes(root, target, "test-scenarios/review-template.md", ["55. verify:rules 正常通过", "69. verify:rules JSON schema 和重复执行", "97. Skill 触发测试"]);
452
- requireIncludes(root, target, "test-scenarios/README.md", ["npm run verify:rules", "v1.7.2-scenarios.md", "v1.7.3-scenarios.md", "v1.10.2-scenarios.md", "当前版本必测场景为 `scenarios.md` 的 1-133", "106 和 119 为观察项"]);
453
- }
454
-
455
- function validateV18Content(root, target) {
456
- const required = [
457
- ["init/xinyun-ai-init/rules/coordination.md", ["factStatus", "changeStatus", "conflictStatus", "coordinationTransactionId", "status-inconsistent"]],
458
- ["init/xinyun-ai-init/rules/skills.md", ["assignmentStatus", "usageStatus", "failureReason", "nextAction", "availabilityStatus", "trustStatus"]],
459
- ["init/xinyun-ai-init/rules/frontend-audit.md", ["audit-only", "refactor-now", "unverifiedScope", "coverage"]],
460
- ["init/xinyun-ai-init/rules/temporary-sessions.md", ["occupancyStatus=unknown", "releaseAudit", "最多同时占用 3 个运行额度"]],
461
- ["test-scenarios/v1.8.0-scenarios.md", ["v1.8-01", "v1.8-08", "forbiddenOperations", "sensitiveScan"]],
462
- ["init/xinyun-ai-init/README.md", ["v1.8", "assignmentStatus", "occupancyStatus=unknown", "coordinationTransactionId"]],
463
- ["init/xinyun-ai-init/templates/core-rules.template.md", ["factStatus", "changeStatus", "conflictStatus", "assignmentStatus", "usageStatus"]],
464
- ["init/xinyun-ai-init/templates/AGENTS.template.md", ["assignments.json.status", "assignmentStatus", "occupancyStatus"]],
465
- ];
466
- for (const [file, snippets] of required) requireIncludes(root, target, file, snippets, "v1.8.content");
467
-
468
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
469
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
470
- const capabilities = manifest.capabilities || {};
471
- for (const flag of ["sharedProjectFactsCoordination", "skillRouting", "frontendCouplingAudit", "temporaryProgrammerSessions"]) {
472
- addCheck(target, "v1.8.capability", "manifest", capabilities[flag] === true ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", `capabilities.${flag}`, true, capabilities[flag], "v1.8 capability checked.", "Register the v1.8 capability.");
473
- }
474
- const pathPairs = [
475
- [manifest.coordination, "directory", "xinyun-ai/coordination/"],
476
- [manifest.skills, "directory", "xinyun-ai/skills/"],
477
- [manifest.frontendAudit, "directory", "xinyun-ai/frontend-audits/"],
478
- [manifest.temporarySessions, "directory", "xinyun-ai/sessions/temporary/"],
479
- [projectIndex.coordination, "directory", "xinyun-ai/coordination/"],
480
- [projectIndex.skills, "directory", "xinyun-ai/skills/"],
481
- [projectIndex.frontendAudit, "directory", "xinyun-ai/frontend-audits/"],
482
- [projectIndex.temporarySessions, "directory", "xinyun-ai/sessions/temporary/"],
483
- ];
484
- for (const [object, field, expected] of pathPairs) addCheck(target, "v1.8.path", "registry", object && object[field] === expected ? "pass" : "fail", "manifest/project-index templates", field, expected, object && object[field], "v1.8 path registration checked.", "Register the v1.8 control path.");
485
-
486
- const assignments = readJson(root, "init/xinyun-ai-init/templates/skills-assignments.template.json");
487
- const transaction = readJson(root, "init/xinyun-ai-init/templates/coordination-transaction.template.json");
488
- const frontend = readJson(root, "init/xinyun-ai-init/templates/frontend-audit.template.json");
489
- const temporary = readJson(root, "init/xinyun-ai-init/templates/temporary-session.template.json");
490
- addCheck(target, "v1.8.assignment.field", "schema", assignments.recordContract.requiredFields.includes("assignmentStatus") ? "pass" : "fail", "skills-assignments.template.json", "assignmentStatus", true, assignments.recordContract.requiredFields.includes("assignmentStatus"), "assignmentStatus field checked.", "Use assignmentStatus.");
491
- addCheck(target, "v1.8.assignment.no-status-alias", "schema", !JSON.stringify(assignments).includes("assignments.json.status") ? "pass" : "fail", "skills-assignments.template.json", null, "no stale status alias", JSON.stringify(assignments), "No stale assignment status alias checked.", "Remove assignments.json.status.");
492
- addCheck(target, "v1.8.transaction.phase", "schema", transaction.phaseEnum.includes("recovery-required") && transaction.phaseEnum.includes("blocked") ? "pass" : "fail", "coordination-transaction.template.json", "phaseEnum", "recovery-required,blocked", transaction.phaseEnum, "Transaction phases checked.", "Restore transaction phase enum.");
493
- addCheck(target, "v1.8.frontend.audit-only", "schema", frontend.decision === "audit-only" && frontend.coverage === "unknown" ? "pass" : "fail", "frontend-audit.template.json", "decision/coverage", "audit-only/unknown", `${frontend.decision}/${frontend.coverage}`, "Frontend audit default checked.", "Use read-only audit defaults.");
494
- addCheck(target, "v1.8.temporary.capacity", "schema", temporary.maxConcurrent === 3 && temporary.occupancyStatusEnum.includes("unknown") ? "pass" : "fail", "temporary-session.template.json", "maxConcurrent/occupancyStatusEnum", "3/unknown", `${temporary.maxConcurrent}/${temporary.occupancyStatusEnum}`, "Temporary session capacity checked.", "Restore capacity and unknown occupancy.");
495
- }
496
-
497
- function validateV171Content(root, target) {
498
- const snippets = [
499
- "项目初始化:<项目显示名>",
500
- "xinyun-ai/tasks/task-index.json",
501
- "xinyun-ai/tasks/.archive-transactions/<archiveTransactionId>.json",
502
- "taskKind=initialization-record",
503
- "taskKind=role-execution",
504
- "executionEligible",
505
- "status=idle",
506
- "taskId=null",
507
- "title=暂无待执行任务",
508
- "codeGraphRecordId",
509
- "codegraph init -i",
510
- "permission-denied",
511
- "degradationAuthorized",
512
- ];
513
- requireIncludes(root, target, "init/xinyun-ai-init/README.md", ["v1.7.1 初始化主任务、角色子任务与归档", "v1.7.1 CodeGraph 必备初始化与状态闭环", ...snippets]);
514
- requireIncludes(root, target, "init/xinyun-ai-init/templates/core-rules.template.md", ["v1.7.1 初始化主任务、角色子任务与归档", "v1.7.1 CodeGraph 必备初始化与状态闭环", ...snippets]);
515
- requireIncludes(root, target, "init/xinyun-ai-init/templates/AGENTS.template.md", ["v1.7.1 初始化任务树与 CodeGraph", ...snippets.slice(0, 11)]);
516
- requireIncludes(root, target, "init/xinyun-ai-init/templates/current-task.template.md", ["初始化任务树", "任务归档", "CodeGraph 必备初始化", "currentTaskIdleStatus:status=idle, taskId=null, title=暂无待执行任务"]);
517
- requireIncludes(root, target, "init/xinyun-ai-init/templates/project-guide.template.md", ["v1.7.1 初始化任务树、归档与 CodeGraph"]);
518
- requireIncludes(root, target, "init/xinyun-ai-init/templates/project-check.template.md", ["v1.7.1 检查", "CodeGraph 失败矩阵"]);
519
- requireIncludes(root, target, "init/xinyun-ai-init/rules/init-rules.md", ["v1.7.1 初始化任务树与 CodeGraph"]);
520
- requireIncludes(root, target, "init/xinyun-ai-init/rules/upgrade-rules.md", ["v1.7.1 升级补齐"]);
521
- requireIncludes(root, target, "init/xinyun-ai-init/rules/directory-self-completion.md", ["v1.7.1 任务树、归档与 CodeGraph 目录"]);
522
- requireIncludes(root, target, "init/xinyun-ai-init/rules/session-workbench.md", ["v1.7.1 任务单补充字段"]);
523
- requireIncludes(root, target, "test-scenarios/scenarios.md", ["当前必测场景为 1-133", "当前观察场景为 106 和 119", "## 71. v1.7.1 主任务命名", "## 87. v1.7.1 普通咨询和版本回归"]);
524
- requireIncludes(root, target, "test-scenarios/v1.7.1-scenarios.md", ["主任务命名", "CodeGraph记录与失败矩阵", "普通咨询边界"]);
525
- }
526
-
527
- function validateV172Content(root, target) {
528
- const snippets = [
529
- "v1.7.2 初始化后角色任务可见性与执行任务分离",
530
- "xinyun-ai/tasks/role-execution/<roleTaskId>.md",
531
- "taskKind=initialization-main",
532
- "taskKind=initialization-record",
533
- "taskKind=role-execution",
534
- "activeTaskIds",
535
- "executableTaskIds",
536
- "priority ASC",
537
- "JCS-SHA-256",
538
- "blockedReason=write-failed",
539
- ];
540
- requireIncludes(root, target, "init/xinyun-ai-init/README.md", ["当前规则版本:`1.9.0`", ...snippets]);
541
- requireIncludes(root, target, "init/xinyun-ai-init/templates/core-rules.template.md", snippets);
542
- requireIncludes(root, target, "init/xinyun-ai-init/rules/init-rules.md", ["v1.7.2 角色后续任务可见性", "role-execution"]);
543
- requireIncludes(root, target, "init/xinyun-ai-init/rules/upgrade-rules.md", ["v1.7.2 升级补建角色后续任务", "write-failed"]);
544
- requireIncludes(root, target, "init/xinyun-ai-init/rules/directory-self-completion.md", ["v1.7.2 任务可见性目录", "role-execution"]);
545
- requireIncludes(root, target, "init/xinyun-ai-init/rules/session-workbench.md", ["v1.7.2 角色执行任务补充字段", "roleExecutionResult"]);
546
- requireIncludes(root, target, "test-scenarios/v1.7.2-scenarios.md", ["固定优先级", "幂等补建", "补建失败和索引恢复"]);
547
- }
548
-
549
- function validateV173Content(root, target) {
550
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
551
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
552
- const taskIndex = readJson(root, "init/xinyun-ai-init/templates/task-index.template.json");
553
- const initResult = readJson(root, "init/xinyun-ai-init/templates/init-result.template.json");
554
- const assignments = readJson(root, "init/xinyun-ai-init/templates/team/assignments.json");
555
- const binding = readJson(root, "init/xinyun-ai-init/templates/role-session-binding.template.json");
556
- const statusEnum = ["pending", "creating", "created", "onboarding", "ready", "blocked", "failed", "closed"];
557
-
558
- addCheck(target, "registry.manifest", "manifest", manifest.capabilities && manifest.capabilities.codexRoleSessionOrchestration === true ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "capabilities.codexRoleSessionOrchestration", true, manifest.capabilities && manifest.capabilities.codexRoleSessionOrchestration, "Codex role session capability checked.", "Register codexRoleSessionOrchestration.");
559
- addCheck(target, "registry.manifest", "manifest", manifest.roleSessions && manifest.roleSessions.provider === "codex" ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "roleSessions.provider", "codex", manifest.roleSessions && manifest.roleSessions.provider, "Role session provider checked.", "Set provider=codex.");
560
- addCheck(target, "registry.manifest", "manifest", manifest.roleSessions && manifest.roleSessions.targetVersion === VERSION ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "roleSessions.targetVersion", VERSION, manifest.roleSessions && manifest.roleSessions.targetVersion, "Role session target version checked.", "Set targetVersion.");
561
- addCheck(target, "registry.manifest", "manifest", manifest.roleSessions && manifest.roleSessions.bindings === "xinyun-ai/sessions/role-session-bindings.json" ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "roleSessions.bindings", "xinyun-ai/sessions/role-session-bindings.json", manifest.roleSessions && manifest.roleSessions.bindings, "Role session binding path checked.", "Register binding path.");
562
- addCheck(target, "registry.manifest", "manifest", manifest.roleSessions && manifest.roleSessions.directory === "xinyun-ai/sessions/roles/" ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "roleSessions.directory", "xinyun-ai/sessions/roles/", manifest.roleSessions && manifest.roleSessions.directory, "Role session directory checked.", "Register role session directory.");
563
- addCheck(target, "registry.manifest", "manifest", manifest.roleSessions && JSON.stringify(manifest.roleSessions.statusEnum) === JSON.stringify(statusEnum) ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "roleSessions.statusEnum", statusEnum, manifest.roleSessions && manifest.roleSessions.statusEnum, "Role session status enum checked.", "Use the fixed v1.7.3 enum.");
564
- addCheck(target, "registry.manifest", "manifest", manifest.roleSessions && manifest.roleSessions.idempotency && JSON.stringify(manifest.roleSessions.idempotency.legacyCreationIndexFields) === JSON.stringify(["taskId", "roleId", "provider", "targetVersion"]) ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "roleSessions.idempotency.legacyCreationIndexFields", ["taskId", "roleId", "provider", "targetVersion"], manifest.roleSessions && manifest.roleSessions.idempotency && manifest.roleSessions.idempotency.legacyCreationIndexFields, "Legacy role session creation index checked.", "Keep legacy fields compatibility-only.");
565
- const v19SessionKeyFields = ["projectRootHash", "workspaceScope", "repositoryScopeHash", "workstream", "taskId", "roleId", "provider", "targetVersion"];
566
- addCheck(target, "registry.manifest", "manifest", manifest.roleSessions && manifest.roleSessions.idempotency && JSON.stringify(manifest.roleSessions.idempotency.keyFields) === JSON.stringify(v19SessionKeyFields) && manifest.roleSessions.idempotency.algorithm === "RFC8785-JCS-SHA-256" ? "pass" : "fail", "init/xinyun-ai-init/templates/manifest.template.json", "roleSessions.idempotency.keyFields", v19SessionKeyFields, manifest.roleSessions && manifest.roleSessions.idempotency && manifest.roleSessions.idempotency.keyFields, "v1.9 project-isolated role session reuse key checked.", "Use the full v1.9 identity key.");
567
- addCheck(target, "registry.project-index", "project-index", projectIndex.roleSessions && projectIndex.roleSessions.provider === "codex" ? "pass" : "fail", "init/xinyun-ai-init/templates/project-index.template.json", "roleSessions.provider", "codex", projectIndex.roleSessions && projectIndex.roleSessions.provider, "Project-index role session provider checked.", "Set provider=codex.");
568
- addCheck(target, "registry.project-index", "project-index", projectIndex.roleSessions && Array.isArray(projectIndex.roleSessions.records) ? "pass" : "fail", "init/xinyun-ai-init/templates/project-index.template.json", "roleSessions.records", "array", projectIndex.roleSessions && projectIndex.roleSessions.records, "Project-index role session records checked.", "Add records array.");
569
- addCheck(target, "registry.project-index", "project-index", projectIndex.roleSessions && projectIndex.roleSessions.idempotency && JSON.stringify(projectIndex.roleSessions.idempotency.keyFields) === JSON.stringify(v19SessionKeyFields) && projectIndex.roleSessions.idempotency.algorithm === "RFC8785-JCS-SHA-256" ? "pass" : "fail", "init/xinyun-ai-init/templates/project-index.template.json", "roleSessions.idempotency.keyFields", v19SessionKeyFields, projectIndex.roleSessions && projectIndex.roleSessions.idempotency && projectIndex.roleSessions.idempotency.keyFields, "Project-index v1.9 reuse key checked.", "Register the full v1.9 identity key.");
570
- addCheck(target, "registry.task-index", "task-index", Array.isArray(taskIndex.roleSessionBindingIds) ? "pass" : "fail", "init/xinyun-ai-init/templates/task-index.template.json", "roleSessionBindingIds", "array", taskIndex.roleSessionBindingIds, "Task-index binding IDs checked.", "Add roleSessionBindingIds.");
571
- addCheck(target, "registry.task-index", "task-index", Array.isArray(taskIndex.roleSessionBindings) ? "pass" : "fail", "init/xinyun-ai-init/templates/task-index.template.json", "roleSessionBindings", "array", taskIndex.roleSessionBindings, "Task-index bindings checked.", "Add roleSessionBindings.");
572
- addCheck(target, "registry.task-index", "task-index", taskIndex.roleSessionIdempotency && JSON.stringify(taskIndex.roleSessionIdempotency.legacyCreationIndexFields) === JSON.stringify(["taskId", "roleId", "provider", "targetVersion"]) ? "pass" : "fail", "init/xinyun-ai-init/templates/task-index.template.json", "roleSessionIdempotency.legacyCreationIndexFields", ["taskId", "roleId", "provider", "targetVersion"], taskIndex.roleSessionIdempotency && taskIndex.roleSessionIdempotency.legacyCreationIndexFields, "Legacy task-index creation index checked.", "Keep legacy fields compatibility-only.");
573
- addCheck(target, "registry.task-index", "task-index", taskIndex.roleSessionIdempotency && JSON.stringify(taskIndex.roleSessionIdempotency.keyFields) === JSON.stringify(v19SessionKeyFields) && taskIndex.roleSessionIdempotency.algorithm === "RFC8785-JCS-SHA-256" ? "pass" : "fail", "init/xinyun-ai-init/templates/task-index.template.json", "roleSessionIdempotency.keyFields", v19SessionKeyFields, taskIndex.roleSessionIdempotency && taskIndex.roleSessionIdempotency.keyFields, "Task-index v1.9 reuse key checked.", "Use the full v1.9 identity key.");
574
- addCheck(target, "registry.init-result", "init-result", initResult.roleSessions && initResult.roleSessions.provider === "codex" ? "pass" : "fail", "init/xinyun-ai-init/templates/init-result.template.json", "roleSessions.provider", "codex", initResult.roleSessions && initResult.roleSessions.provider, "Init-result role session provider checked.", "Set provider=codex.");
575
- addCheck(target, "registry.assignments", "assignments", assignments.recordContract && assignments.recordContract.requiredFields.includes("sessionStatus") ? "pass" : "fail", "init/xinyun-ai-init/templates/team/assignments.json", "recordContract.requiredFields", "sessionStatus", assignments.recordContract && assignments.recordContract.requiredFields, "Assignments sessionStatus checked.", "Add sessionStatus to assignments contract.");
576
- addCheck(target, "registry.binding-template", "template", binding.provider === "codex" && binding.targetVersion === VERSION && binding.degradation && binding.degradation.fakeSessionIdProhibited === true ? "pass" : "fail", "init/xinyun-ai-init/templates/role-session-binding.template.json", "provider/targetVersion/degradation", "codex / version / fakeSessionIdProhibited", binding, "Role session binding template checked.", "Fix binding template.");
577
-
578
- const snippets = [
579
- "v1.7.3 Codex 角色会话自动创建与绑定",
580
- "provider=codex",
581
- "sessionStatus=pending/creating/created/onboarding/ready/blocked/failed/closed",
582
- "projectRootHash, workspaceScope, repositoryScopeHash, workstream, taskId, roleId, provider, targetVersion",
583
- "RFC8785-JCS-SHA-256",
584
- "不得伪造 sessionId",
585
- "local-degraded-no-fake-session-id",
586
- "created-but-writeback-failed",
587
- "创建成功不等于业务代码修改授权",
588
- ];
589
- requireIncludes(root, target, "init/xinyun-ai-init/README.md", ["当前规则版本:`1.9.0`", ...snippets]);
590
- requireIncludes(root, target, "init/xinyun-ai-init/templates/core-rules.template.md", snippets);
591
- requireIncludes(root, target, "init/xinyun-ai-init/templates/AGENTS.template.md", ["v1.7.3 Codex 角色会话自动创建与绑定", "provider=codex", "local-degraded-no-fake-session-id"]);
592
- requireIncludes(root, target, "init/xinyun-ai-init/rules/init-rules.md", ["v1.7.3 Codex 角色会话初始化", "provider=codex", "local-degraded-no-fake-session-id"]);
593
- requireIncludes(root, target, "init/xinyun-ai-init/rules/upgrade-rules.md", ["v1.7.3 升级创建和绑定真实角色会话", "created-but-writeback-failed", "不得伪造 sessionId"]);
594
- requireIncludes(root, target, "init/xinyun-ai-init/rules/session-workbench.md", ["v1.7.3 角色会话交接字段", "roleSessionIdempotency", "不得伪造 sessionId"]);
595
- requireIncludes(root, target, "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"]);
596
- requireIncludes(root, target, "test-scenarios/v1.7.3-scenarios.md", ["五个真实角色子会话创建", "会话绑定回写一致性", "onboarding 只读边界", "宿主不支持时本地降级"]);
597
- requireIncludes(root, target, "test-scenarios/scenarios.md", ["当前必测场景为 1-133", "当前观察场景为 106 和 119", "## 89. v1.7.3 Codex 真实角色会话创建", "## 96. v1.7.3 普通咨询边界"]);
598
- }
599
-
600
- function validateV19Content(root, target) {
601
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
602
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
603
- const identity = readJson(root, "init/xinyun-ai-init/templates/project-identity.template.json");
604
- const candidates = readJson(root, "init/xinyun-ai-init/templates/session-candidates.template.json");
605
- const landscape = readJson(root, "init/xinyun-ai-init/templates/technical-landscape.template.json");
606
- const requirement = readJson(root, "init/xinyun-ai-init/templates/requirement-packet.template.json");
607
- const impact = readJson(root, "init/xinyun-ai-init/templates/technical-impact-packet.template.json");
608
- const database = readJson(root, "init/xinyun-ai-init/templates/database-authorization.template.json");
609
- const behaviorEvidence = readJson(root, "test-scenarios/v1.9.0-behavior-evidence.json");
610
- const v19Paths = {
611
- projectIdentity: "xinyun-ai/project-identity.json",
612
- sessionCandidates: "xinyun-ai/sessions/session-candidates.json",
613
- technicalLandscape: "xinyun-ai/technical-landscape.json",
614
- requirementPacket: "xinyun-ai/packets/requirement-packet.json",
615
- technicalImpactPacket: "xinyun-ai/packets/technical-impact-packet.json",
616
- databaseAuthorization: "xinyun-ai/database/authorization.json",
617
- };
618
-
619
- for (const [key, expected] of Object.entries(v19Paths)) {
620
- const actual = manifest.v19 && manifest.v19[key];
621
- const indexActual = projectIndex.v19 && projectIndex.v19[key];
622
- addCheck(target, "v1.9.path", "registry", actual === expected && indexActual === expected ? "pass" : "fail", "manifest/project-index.v19", key, expected, { manifest: actual, projectIndex: indexActual }, "v1.9 path registration checked.", "Register the v1.9 control path.");
623
- }
624
- addCheck(target, "v1.9.capability", "manifest", manifest.capabilities && manifest.capabilities.projectSessionIsolation === true ? "pass" : "fail", "manifest.template.json", "capabilities.projectSessionIsolation", true, manifest.capabilities && manifest.capabilities.projectSessionIsolation, "Project session isolation checked.", "Register v1.9 capability.");
625
- addCheck(target, "v1.9.identity", "schema", identity.normalization && identity.normalization.unicodeNormalization === "NFC" && identity.normalization.resolutionMode === "unknown" ? "pass" : "fail", "project-identity.template.json", "normalization", "NFC/unknown", identity.normalization, "Project identity normalization checked.", "Restore identity normalization.");
626
- addCheck(target, "v1.9.session-status", "schema", candidates.sessionMatchStatusEnum && !candidates.sessionMatchStatusEnum.includes("current-match") && candidates.sessionMatchStatusEnum.includes("reusable") ? "pass" : "fail", "session-candidates.template.json", "sessionMatchStatusEnum", "no current-match/reusable", candidates.sessionMatchStatusEnum, "Session candidate status checked.", "Restore session candidate states.");
627
- addCheck(target, "v1.9.session-evidence", "schema", candidates.candidateRequiredFields && ["hostRecoveryAvailable", "hostRecoveryEvidence"].every((field) => candidates.candidateRequiredFields.includes(field)) ? "pass" : "fail", "session-candidates.template.json", "candidateRequiredFields", "recovery evidence", candidates.candidateRequiredFields, "Session recovery evidence checked.", "Add recovery evidence fields.");
628
- addCheck(target, "v1.9.landscape-ready", "schema", landscape.status === "not-started" && landscape.coverage.coverageStatus === "unknown" && Array.isArray(landscape.unverifiedScope) ? "pass" : "fail", "technical-landscape.template.json", "status/coverage", "not-started/unknown", landscape, "Technical landscape gate checked.", "Restore conservative landscape defaults.");
629
- const packetFields = ["schemaVersion", "packetId", "requirementId", "taskId", "projectRootHash", "version", "status", "content", "evidence", "sourceRevision", "contentHash", "createdAt", "updatedAt"];
630
- addCheck(target, "v1.9.packet-schema", "schema", [requirement, impact].every((packet) => packetFields.every((field) => Object.prototype.hasOwnProperty.call(packet, field))) ? "pass" : "fail", "packet templates", "minimum fields", packetFields, "requirement/impact packet fields", "Packet schema checked.", "Restore packet fields.");
631
- addCheck(target, "v1.9.database-local-files-read-only", "schema", 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 ? "pass" : "fail", "database-authorization.template.json", "databaseAccessMode/executionStatus/connectionStatus", "local-files-read-only/needs-confirmation/not-requested", `${database.databaseAccessMode}/${database.executionStatus}/${database.connectionStatus}`, "Database local-file read-only default checked.", "Restore local-file read-only defaults.");
632
- const localDatabaseScope = ["*.sql", "*.ddl", "*.schema", "*.migration", "database/", "migrations/", "schema/", "models/"];
633
- addCheck(target, "v1.9.database-local-file-policy", "schema", JSON.stringify(database.localDatabaseFileScope) === JSON.stringify(localDatabaseScope) && database.localFileReadPolicy === "database-related-task-only" && database.forbiddenOperations.includes("database-connection") && database.forbiddenOperations.includes("sql-execution") ? "pass" : "fail", "database-authorization.template.json", "localDatabaseFileScope/localFileReadPolicy/forbiddenOperations", "database-related local text files only", database, "Database local-file scope and forbidden operations checked.", "Restrict database access to local files and prohibit connections/execution.");
634
- addCheck(target, "v1.9.database-policy-across-control-plane", "schema", 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" ? "pass" : "fail", "manifest/project-index.v19", "database policy", "local-files-read-only/generate-only/sql-only legacy", {manifest: manifest.v19, projectIndex: projectIndex.v19}, "Database policy is consistent across v1.9 registries.", "Synchronize the v1.9 database policy.");
635
- addCheck(target, "v1.9.database-permissions", "schema", ["connectionStatus", "queryAuthorization", "schemaChangeAuthorization", "dataMutationAuthorization"].every((field) => Object.prototype.hasOwnProperty.call(database, field)) ? "pass" : "fail", "database-authorization.template.json", "authorization fields", "four independent fields", database, "Database authorization separation checked.", "Separate database permissions.");
636
- const authorizationStates = ["not-requested", "requested", "authorized", "denied", "expired", "failed", "unknown"];
637
- addCheck(target, "v1.9.database-authorization-state-enum", "schema", database.authorizationStatusEnum && JSON.stringify(database.authorizationStatusEnum) === JSON.stringify(authorizationStates) && ["connectionStatusEnum", "queryAuthorizationEnum", "schemaChangeAuthorizationEnum", "dataMutationAuthorizationEnum"].every((field) => JSON.stringify(database[field]) === JSON.stringify(authorizationStates)) ? "pass" : "fail", "database-authorization.template.json", "authorizationStatusEnum", authorizationStates, database.authorizationStatusEnum, "Database authorization status enum checked.", "Fix authorization status enums.");
638
- addCheck(target, "v1.9.database-authorization-transitions", "schema", database.authorizationTransitionRules && database.authorizationTransitionRules.authorized.includes("expired") && database.invalidatingChanges.includes("statement-hash-changed") && database.invalidatingAction.includes("needs-confirmation") ? "pass" : "fail", "database-authorization.template.json", "authorizationTransitionRules", "authorized->expired and needs-confirmation", database.authorizationTransitionRules, "Authorization invalidation transitions checked.", "Add expiration and re-confirmation rules.");
639
- addCheck(target, "v1.9.database-redaction-enum", "schema", JSON.stringify(database.redactionStatusEnum) === JSON.stringify(["verified", "unverified", "failed"]) && database.redactionStatus === "verified" ? "pass" : "fail", "database-authorization.template.json", "redactionStatusEnum", ["verified", "unverified", "failed"], database.redactionStatusEnum, "Redaction status checked.", "Fix redaction status enum.");
640
- addCheck(target, "v1.9.database-execution-state-enum", "schema", JSON.stringify(database.executionStatusEnum) === JSON.stringify(["not-run", "needs-confirmation", "authorized", "executed", "failed", "unknown"]) ? "pass" : "fail", "database-authorization.template.json", "executionStatusEnum", "needs-confirmation", database.executionStatusEnum, "Execution state checked.", "Fix execution status enum.");
641
- addCheck(target, "v1.9.behavior-evidence", "behavior", behaviorEvidence.evidenceType === "behavioral-replay" && behaviorEvidence.realAiSessionVerified === false && Array.isArray(behaviorEvidence.scenarios) && JSON.stringify(behaviorEvidence.scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(Array.from({ length: 12 }, (_, index) => 107 + index)) && behaviorEvidence.scenarios.every((scenario) => scenario.result === "replay-passed" && scenario.sensitiveScan && scenario.sensitiveScan.matches.length === 0) ? "pass" : "fail", "test-scenarios/v1.9.0-behavior-evidence.json", "scenarios", "107-118 replay-passed without sensitive matches", behaviorEvidence.scenarios, "v1.9 controlled behavior replay evidence checked.", "Provide complete auditable v1.9 evidence.");
642
- const crossProjectScenario = Array.isArray(behaviorEvidence.scenarios) ? behaviorEvidence.scenarios.find((scenario) => scenario.scenarioId === 109) : null;
643
- addCheck(target, "v1.9.cross-project-negative", "behavior", crossProjectScenario && crossProjectScenario.input.includes("projectRootHash") && crossProjectScenario.actualOutput.includes("other-project") && crossProjectScenario.afterSnapshot.includes("createdCount=0") ? "pass" : "fail", "test-scenarios/v1.9.0-behavior-evidence.json", "scenario 109", "different project rejected without duplicate", crossProjectScenario, "Cross-project reuse negative evidence checked.", "Add the v1.9 cross-project negative evidence.");
644
- validateV19SessionReuseText(root, target);
645
- addCheck(target, "v1.9.statement-hash", "schema", database.statementHashAlgorithm === "RFC8785-JCS-SHA-256" && database.statementHashCanonicalInput.includes("parameters") && database.statementHashCanonicalInput.includes("targetEnvironment") ? "pass" : "fail", "database-authorization.template.json", "statementHash", "RFC8785-JCS-SHA-256", database.statementHashAlgorithm, "Statement hash checked.", "Restore statement hash canonical input.");
646
- requireIncludes(root, target, "test-scenarios/v1.9.0-scenarios.md", ["## 107.", "## 113.", "## 115.", "## 118.", "sql-only", "packet-stale", "行为证据"], "v1.9.content");
647
- requireIncludes(root, target, "init/xinyun-ai-init/README.md", ["v1.9", "lexical-fallback", "sessionMatchStatus", "technical-landscape", "packet-stale", "databaseAccessMode=local-files-read-only", "legacyDatabaseAccessMode=sql-only", "statementHash"], "v1.9.content");
648
- }
649
-
650
- function validateV110Content(root, target) {
651
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
652
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
653
- const host = readJson(root, "init/xinyun-ai-init/templates/host-capabilities.template.json");
654
- const projectStatus = readJson(root, "init/xinyun-ai-init/templates/project-status.template.json");
655
- const preflight = readJson(root, "init/xinyun-ai-init/templates/preflight-report.template.json");
656
- const onboarding = readJson(root, "init/xinyun-ai-init/templates/onboarding-report.template.json");
657
- const baseline = readJson(root, "init/xinyun-ai-init/templates/takeover-baseline.template.json");
658
- const controlPlane = readJson(root, "init/xinyun-ai-init/templates/control-plane-index.template.json");
659
- const initResult = readJson(root, "init/xinyun-ai-init/templates/init-result.template.json");
660
- const currentTask = readText(root, "init/xinyun-ai-init/templates/current-task.template.md");
661
- const requiredFiles = [
662
- "init/xinyun-ai-init/templates/host-capabilities.template.json",
663
- "init/xinyun-ai-init/templates/project-status.template.json",
664
- "init/xinyun-ai-init/templates/preflight-report.template.json",
665
- "init/xinyun-ai-init/templates/onboarding-report.template.json",
666
- "init/xinyun-ai-init/templates/takeover-baseline.template.json",
667
- "init/xinyun-ai-init/templates/control-plane-index.template.json",
668
- "init/xinyun-ai-init/templates/init-result.template.json",
669
- "init/xinyun-ai-init/templates/current-task.template.md",
670
- "test-scenarios/v1.10.0-scenarios.md",
671
- "test-scenarios/v1.10.0-behavior-evidence.json",
672
- "scripts/collect-v1.10-evidence.js",
673
- "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/README.md",
674
- "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/before/project-status.json",
675
- "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/after/project-status.json",
676
- ];
677
- for (const file of requiredFiles) requireFile(root, target, file);
678
-
679
- const paths = {
680
- projectStatus: "xinyun-ai/project-status.json",
681
- preflightReport: "xinyun-ai/preflight-report.json",
682
- onboardingReport: "xinyun-ai/onboarding-report.json",
683
- hostCapabilities: "xinyun-ai/host-capabilities.json",
684
- takeoverBaseline: "xinyun-ai/index/takeover-baseline.json",
685
- controlPlaneIndex: "xinyun-ai/index/control-plane-index.json",
686
- };
687
- for (const [key, expected] of Object.entries(paths)) {
688
- addCheck(target, "v1.10.path", "registry", manifest.v110 && manifest.v110[key] === expected ? "pass" : "fail", "manifest.template.json", `v110.${key}`, expected, manifest.v110 && manifest.v110[key], "v1.10 manifest path checked.", "Register the v1.10 control path.");
689
- addCheck(target, "v1.10.path", "registry", projectIndex.v110 && projectIndex.v110[key] === expected ? "pass" : "fail", "project-index.template.json", `v110.${key}`, expected, projectIndex.v110 && projectIndex.v110[key], "v1.10 project-index path checked.", "Register the v1.10 control path.");
690
- }
691
- const statuses = ["not-started", "initializing", "partial", "blocked", "ready"];
692
- addCheck(target, "v1.10.status-gate", "schema", manifest.v110 && JSON.stringify(manifest.v110.projectStatusEnum) === JSON.stringify(statuses) && manifest.v110.requiredRoleSessionBlockedReason === "required-role-session-not-created" ? "pass" : "fail", "manifest.template.json", "v110", "project status gate", manifest.v110, "v1.10 status gate checked.", "Restore the v1.10 status gate.");
693
- addCheck(target, "v1.10.host-capabilities", "schema", host.status === "unknown" && host.readyPolicy && host.readyPolicy.fakeSessionIdProhibited === true && host.readyPolicy.requiredCapabilities.length === 6 ? "pass" : "fail", "host-capabilities.template.json", "readyPolicy", "unknown and six required capabilities", host, "Host capability gate checked.", "Restore conservative host capability defaults.");
694
- addCheck(target, "v1.10.preflight", "schema", preflight.result === "not-run" && preflight.codeGraph.command === "codegraph init -i" && Array.isArray(preflight.unverifiedScope) ? "pass" : "fail", "preflight-report.template.json", "result/codeGraph/unverifiedScope", "not-run/codegraph init -i", preflight, "Preflight contract checked.", "Restore preflight fields.");
695
- addCheck(target, "v1.10.onboarding", "schema", onboarding.executionEligible === false && onboarding.roleSessionContract.realSessionIdRequired === true && onboarding.requiredRoleIds.length === 5 ? "pass" : "fail", "onboarding-report.template.json", "roleSessionContract", "real sessions required", onboarding.roleSessionContract, "Onboarding role gate checked.", "Restore onboarding role gate.");
696
- addCheck(target, "v1.10.baseline", "schema", baseline.hashAlgorithm === "SHA-256" && baseline.git.writePerformed === false && baseline.businessFiles && baseline.controlFiles ? "pass" : "fail", "takeover-baseline.template.json", "hashAlgorithm/git/businessFiles/controlFiles", "SHA-256/read-only", baseline, "Takeover baseline checked.", "Restore takeover baseline fields.");
697
- addCheck(target, "v1.10.control-plane", "schema", controlPlane.atomicWriteContract && controlPlane.atomicWriteContract.tempFileRequired === true && controlPlane.atomicWriteContract.fsyncBeforeRename === true && controlPlane.idempotency.duplicatePolicy === "reuse-and-audit" ? "pass" : "fail", "control-plane-index.template.json", "atomicWriteContract/idempotency", "atomic and idempotent", controlPlane, "Control plane contract checked.", "Restore atomic and idempotent write rules.");
698
- addCheck(target, "v1.10.database-default", "schema", preflight.database && preflight.database.authorization === "not-requested" && preflight.database.executionStatus === "needs-confirmation" && preflight.database.redactionStatus === "verified" && preflight.database.connected === false ? "pass" : "fail", "preflight-report.template.json", "database", "not-requested/needs-confirmation/verified/not connected", preflight.database, "Database default authorization checked.", "Restore SQL-only database defaults.");
699
- addCheck(target, "v1.10.init-result-database-default", "schema", initResult.databaseAuthorization && initResult.databaseAuthorization.authorization === "not-requested" && initResult.databaseAuthorization.executionStatus === "needs-confirmation" && initResult.databaseAuthorization.redactionStatus === "verified" && initResult.databaseAuthorization.connected === false ? "pass" : "fail", "init-result.template.json", "databaseAuthorization", "not-requested/needs-confirmation/verified/not connected", initResult.databaseAuthorization, "Init-result database default checked.", "Restore init-result database defaults.");
700
- addCheck(target, "v1.10.database-defaults-across-control-plane", "schema", 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 ? "pass" : "fail", "manifest/project-index/preflight/init-result", "database defaults", "not-requested/needs-confirmation/verified", { manifest: manifest.v110 && manifest.v110.databaseDefault, projectIndex: projectIndex.v110 && projectIndex.v110.databaseDefault, preflight: preflight.database, initResult: initResult.databaseAuthorization }, "Database defaults are consistent across the control plane.", "Synchronize database defaults across control files.");
701
- const localDatabaseScope = ["*.sql", "*.ddl", "*.schema", "*.migration", "database/", "migrations/", "schema/", "models/"];
702
- addCheck(target, "v1.10.database-local-file-policy-across-control-plane", "schema", 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) ? "pass" : "fail", "preflight/init-result", "database policy", "local-files-read-only/generate-only/not connected", {preflight: preflight.database, initResult: initResult.databaseAuthorization}, "Database policy is consistent across preflight and init-result.", "Synchronize local-file database policy across control files.");
703
- validateV110CodeGraphContract(root, target, manifest, projectIndex, preflight, onboarding, initResult, currentTask);
704
- validateV110HostCapabilityContract(target, host, projectStatus);
705
- const capabilityStatuses = ["available", "available-with-dependency", "unavailable", "permission-denied", "unknown", "not-checked", "not-verified", "failed"];
706
- const capabilityStatusText = capabilityStatuses.join(" / ");
707
- const projectGuide = readText(root, "init/xinyun-ai-init/templates/project-guide.template.md");
708
- addCheck(target, "v1.10.capability-enum-across-templates", "schema", projectIndex.tasking && projectIndex.tasking.stateMachine && JSON.stringify(projectIndex.tasking.stateMachine.capabilityStatus) === JSON.stringify(capabilityStatuses) && currentTask.includes(capabilityStatusText) && projectGuide.includes(capabilityStatusText) ? "pass" : "fail", "project-index/current-task/project-guide", "capabilityStatus", capabilityStatuses, { projectIndex: projectIndex.tasking && projectIndex.tasking.stateMachine && projectIndex.tasking.stateMachine.capabilityStatus, currentTask: capabilityStatusText, projectGuide: capabilityStatusText }, "Capability status enum is consistent across templates.", "Synchronize the complete capability status enum.");
709
-
710
- requireIncludes(root, target, "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"]);
711
- requireIncludes(root, target, "init/xinyun-ai-init/templates/core-rules.template.md", ["v1.10", "projectStatus", "executionEligible", "required-role-session-not-created", "不得伪造 sessionId"]);
712
- requireIncludes(root, target, "init/xinyun-ai-init/rules/init-rules.md", ["v1.10", "preflight", "projectStatus", "codegraph init -i", "required-role-session-not-created"]);
713
- requireIncludes(root, target, "init/xinyun-ai-init/rules/upgrade-rules.md", ["v1.10", "projectStatus", "required-role-session-not-created"]);
714
- requireIncludes(root, target, "init/xinyun-ai-init/rules/session-workbench.md", ["v1.10", "真实 sessionId", "不得伪造 sessionId", "executionEligible"]);
715
- requireIncludes(root, target, "init/xinyun-ai-init/templates/current-task.template.md", ["statusSource:xinyun-ai/manifest.json", "sourceRevision:", "indexScope:", "unindexedScope:", "available / available-with-dependency / unavailable / permission-denied / unknown / not-checked / not-verified / failed"]);
716
- requireIncludes(root, target, "init/xinyun-ai-init/templates/project-guide.template.md", ["available / available-with-dependency / unavailable / permission-denied / unknown / not-checked / not-verified / failed"]);
717
- requireIncludes(root, target, "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", "状态源缺失"]);
718
- requireIncludes(root, target, "scripts/collect-v1.10-evidence.js", ["codex-host-returned", "real-role-session-host-export-missing", "realAiSessionVerified", "recordHash"]);
719
-
720
- const report = readJson(root, "test-scenarios/v1.10.0-behavior-evidence.json");
721
- const scenarios = Array.isArray(report.scenarios) ? report.scenarios : [];
722
- const expectedIds = Array.from({ length: 14 }, (_, index) => 120 + index);
723
- addCheck(target, "v1.10.behavior-evidence", "behavior", report.evidenceType === "not-verified" && report.executionMode === "host-capability-unavailable" && report.realAiSessionVerified === false && report.publishBlocked === true && report.fixturePath === "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture" && existsFile(root, "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/before/project-status.json") && existsFile(root, "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/after/project-status.json") && JSON.stringify(scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(expectedIds) && scenarios.every((scenario) => scenario.result === "not-verified" && scenario.sessionId === null && scenario.sensitiveScan && scenario.sensitiveScan.matches.length === 0) ? "pass" : "fail", "test-scenarios/v1.10.0-behavior-evidence.json", "scenarios", "120-133 not-verified with persistent fixture boundary", report, "v1.10 evidence source and no-fabrication policy checked.", "Provide truthful real-session evidence or keep the release blocked.");
724
- }
725
-
726
- function validateV110CodeGraphContract(root, target, manifest, projectIndex, preflight, onboarding, initResult, currentTask) {
727
- const source = manifest.codeGraphRequired;
728
- const summaryFields = ["codeGraphRecordId", "statusSource", "status", "sourceRevision", "indexScope", "unindexedScope", "failureReason", "evidence"];
729
- const sameSummary = (record) => record && summaryFields.every((field) => JSON.stringify(record[field]) === JSON.stringify(source[field]));
730
- addCheck(target, "v1.10.codegraph-source", "schema", source && source.statusSource === "xinyun-ai/manifest.json" && source.required === true ? "pass" : "fail", "manifest.template.json", "codeGraphRequired.statusSource", "xinyun-ai/manifest.json", source, "Manifest is the CodeGraph status source.", "Use manifest.codeGraphRequired as the only status source.");
731
- addCheck(target, "v1.10.codegraph-project-index", "schema", sameSummary(projectIndex.codeGraphRequired) ? "pass" : "fail", "project-index.template.json", "codeGraphRequired", "manifest summary", projectIndex.codeGraphRequired, "Project-index mirrors the manifest CodeGraph summary.", "Synchronize project-index CodeGraph fields.");
732
- addCheck(target, "v1.10.codegraph-preflight", "schema", sameSummary(preflight.codeGraph) ? "pass" : "fail", "preflight-report.template.json", "codeGraph", "manifest summary", preflight.codeGraph, "Preflight mirrors the manifest CodeGraph summary.", "Synchronize preflight CodeGraph fields.");
733
- addCheck(target, "v1.10.codegraph-onboarding", "schema", onboarding.codeGraphRecordId === source.codeGraphRecordId && sameSummary({ ...onboarding.codeGraph, codeGraphRecordId: onboarding.codeGraphRecordId }) ? "pass" : "fail", "onboarding-report.template.json", "codeGraph", "manifest summary", onboarding.codeGraph, "Onboarding mirrors the manifest CodeGraph summary.", "Synchronize onboarding CodeGraph fields.");
734
- addCheck(target, "v1.10.codegraph-init-result", "schema", sameSummary(initResult.codeGraph) ? "pass" : "fail", "init-result.template.json", "codeGraph", "manifest summary", initResult.codeGraph, "Init-result mirrors the manifest CodeGraph summary.", "Synchronize init-result CodeGraph fields.");
735
- addCheck(target, "v1.10.codegraph-fields", "schema", ["sourceRevision", "indexScope", "unindexedScope", "failureReason", "evidence"].every((field) => Object.prototype.hasOwnProperty.call(source, field)) ? "pass" : "fail", "manifest.template.json", "codeGraphRequired", "range and failure evidence fields", source, "CodeGraph range and failure fields checked.", "Add CodeGraph range and failure evidence fields.");
736
- addCheck(target, "v1.10.codegraph-current-task", "schema", ["statusSource:xinyun-ai/manifest.json", "sourceRevision:", "indexScope:", "unindexedScope:", "failureReason:"].every((field) => currentTask.includes(field)) ? "pass" : "fail", "current-task.template.md", "CodeGraph summary", "status source and range fields", currentTask, "Current-task CodeGraph summary checked.", "Add CodeGraph summary fields to current-task.");
737
- }
738
-
739
- function validateV110HostCapabilityContract(target, host, projectStatus) {
740
- const requiredFields = ["capabilityId", "detectionMethod", "status", "evidence", "dependencyStatus", "fallbackPlan", "usedTools", "unusedTools", "unverifiedScope", "failureReason", "checkedAt"];
741
- const statuses = ["available", "available-with-dependency", "unavailable", "permission-denied", "unknown", "not-checked", "not-verified", "failed"];
742
- const dependencyStatuses = ["not-required", "required", "authorized", "not-authorized", "unknown"];
743
- const capabilities = host && host.capabilities ? Object.values(host.capabilities) : [];
744
- addCheck(target, "v1.10.host-status-enum", "schema", JSON.stringify(host.statusEnum) === JSON.stringify(statuses) ? "pass" : "fail", "host-capabilities.template.json", "statusEnum", statuses, host.statusEnum, "Host capability statuses checked.", "Restore the complete host capability status enum.");
745
- addCheck(target, "v1.10.host-dependency-enum", "schema", JSON.stringify(host.dependencyStatusEnum) === JSON.stringify(dependencyStatuses) ? "pass" : "fail", "host-capabilities.template.json", "dependencyStatusEnum", dependencyStatuses, host.dependencyStatusEnum, "Dependency statuses checked.", "Restore the dependency status enum.");
746
- addCheck(target, "v1.10.host-minimum-fields", "schema", capabilities.length === 6 && capabilities.every((capability) => requiredFields.every((field) => Object.prototype.hasOwnProperty.call(capability, field))) ? "pass" : "fail", "host-capabilities.template.json", "capabilities", requiredFields, capabilities, "Host capability minimum fields checked.", "Add the host capability evidence fields.");
747
- addCheck(target, "v1.10.host-dependency-gate", "schema", host.readyPolicy && host.readyPolicy.availableWithDependencyBlocksReady === true && host.readyPolicy.notVerifiedBlocksReady === true && host.readyPolicy.blockedStatuses.includes("not-verified") && host.readyPolicy.dependencyRequiredStatus === "authorized" && host.readyPolicy.fakeSessionIdProhibited === true ? "pass" : "fail", "host-capabilities.template.json", "readyPolicy", "dependency authorization and not-verified required", host.readyPolicy, "Dependency authorization gate checked.", "Block ready until dependencies are authorized and verified.");
748
- const blockedStatuses = ["unknown", "unavailable", "permission-denied", "failed", "available-with-dependency", "not-checked", "not-verified"];
749
- addCheck(target, "v1.10.project-ready-capability-gate", "schema", projectStatus.readyPolicy && blockedStatuses.every((status) => projectStatus.readyPolicy.requiredCapabilityBlockedStatuses.includes(status)) && projectStatus.readyPolicy.availableWithDependencyRequires.includes("dependencyStatus=authorized") ? "pass" : "fail", "project-status.template.json", "readyPolicy", "dependency and unknown statuses block ready", projectStatus.readyPolicy, "Project ready capability gate checked.", "Block ready for unavailable or unverified capabilities.");
750
- }
751
-
752
- function validateV111Content(root, target) {
753
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
754
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
755
- const fixedMaterialization = readJson(root, "init/xinyun-ai-init/templates/fixed-materialization.template.json");
756
- const bootstrapSnapshot = readJson(root, "init/xinyun-ai-init/templates/bootstrap-snapshot.template.json");
757
- const stages = readJson(root, "init/xinyun-ai-init/templates/initialization-stages.template.json");
758
- const cache = readJson(root, "init/xinyun-ai-init/templates/initialization-cache.template.json");
759
- const parallelism = readJson(root, "init/xinyun-ai-init/templates/parallelism.template.json");
760
- const stageIds = ["preflight", "fixed-materialization", "control-plane", "codegraph", "bootstrap-snapshot", "role-sessions", "onboarding", "final-gate"];
761
- const stageStatuses = ["pending", "running", "completed", "skipped", "partial", "blocked", "recovery-required"];
762
- const paths = {
763
- fixedMaterialization: "xinyun-ai/fixed-materialization.json",
764
- initializationStages: "xinyun-ai/initialization-stages.json",
765
- bootstrapSnapshot: "xinyun-ai/bootstrap-snapshot.json",
766
- initializationCache: "xinyun-ai/index/initialization-cache.json",
767
- parallelism: "xinyun-ai/sessions/parallelism.json",
768
- };
769
- for (const [key, expected] of Object.entries(paths)) {
770
- addCheck(target, "v1.11.registry." + key, "registry", manifest.v111 && projectIndex.v111 && manifest.v111[key] === expected && projectIndex.v111[key] === expected ? "pass" : "fail", "manifest/project-index.v111", key, expected, {manifest: manifest.v111 && manifest.v111[key], projectIndex: projectIndex.v111 && projectIndex.v111[key]}, "v1.11 path registration checked.", "Register the v1.11 control path.");
771
- }
772
- addCheck(target, "v1.11.stage-schema", "schema", JSON.stringify(stages.stages.map((stage) => stage.stageId)) === JSON.stringify(stageIds) && JSON.stringify(stages.stageStatusEnum) === JSON.stringify(stageStatuses) ? "pass" : "fail", "initialization-stages.template.json", "stages/status", stageIds, stages, "Initialization stage order and states checked.", "Restore the fixed v1.11 stage contract.");
773
- addCheck(target, "v1.11.fixed-materialization", "schema", fixedMaterialization.targetVersion === "1.11.0" && fixedMaterialization.statusEnum.includes("conflict-pending") && fixedMaterialization.atomicWrite && fixedMaterialization.atomicWrite.rename === true ? "pass" : "fail", "fixed-materialization.template.json", "conflict/atomic write", "conflict-pending and atomic rename", fixedMaterialization, "Fixed materialization contract checked.", "Block overwrite and use atomic writes.");
774
- addCheck(target, "v1.11.snapshot-cache", "schema", bootstrapSnapshot.scanBudget.maxDepth === 3 && Array.isArray(bootstrapSnapshot.unverifiedScope) && cache.ttlHours === 24 && cache.keyAlgorithm === "RFC8785-JCS-SHA-256" ? "pass" : "fail", "bootstrap-snapshot/initialization-cache", "budget/cache", "depth=3/ttl=24/JCS", {snapshot: bootstrapSnapshot, cache}, "Bounded snapshot and cache contract checked.", "Restore bounded cache behavior.");
775
- addCheck(target, "v1.11.parallelism", "schema", parallelism.maxConcurrency === 3 && parallelism.requestedConcurrency === 3 && manifest.v111.defaultRoleConcurrency === 3 ? "pass" : "fail", "parallelism.template.json", "maxConcurrency", 3, parallelism, "Parallel role-session limit checked.", "Keep the default concurrency at three.");
776
- requireFile(root, target, "init/xinyun-ai-init/rules/v1.10.2-contract.md");
777
- requireFile(root, target, "init/xinyun-ai-init/rules/v1.11.0-acceleration.md");
778
- requireIncludes(root, target, "init/xinyun-ai-init/README.md", ["v1.10.2", "v1.11.0", "最多 3 个角色并发"]);
779
- requireIncludes(root, target, "init/xinyun-ai-init/rules/init-rules.md", ["v1.10.2 and v1.11.0 gate", "fixed-materialization", "bootstrap-snapshot"]);
780
- }
781
-
782
- function validateV112Content(root, target) {
783
- const requiredFiles = [
784
- "init/xinyun-ai-init/rules/v1.12.0-recovery.md",
785
- "init/xinyun-ai-init/templates/host-preflight.template.json",
786
- "init/xinyun-ai-init/templates/initialization-recovery.template.json",
787
- "init/xinyun-ai-init/templates/manual-session-binding.template.json",
788
- "init/xinyun-ai-init/templates/shared-project-snapshot.template.json",
789
- "init/xinyun-ai-init/templates/initialization-timing.template.json",
790
- "test-scenarios/v1.12.0-scenarios.md",
791
- "test-scenarios/v1.12.0-behavior-evidence.json",
792
- ];
793
- for (const file of requiredFiles) requireFile(root, target, file);
794
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
795
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
796
- const host = readJson(root, "init/xinyun-ai-init/templates/host-preflight.template.json");
797
- const recovery = readJson(root, "init/xinyun-ai-init/templates/initialization-recovery.template.json");
798
- const binding = readJson(root, "init/xinyun-ai-init/templates/manual-session-binding.template.json");
799
- const snapshot = readJson(root, "init/xinyun-ai-init/templates/shared-project-snapshot.template.json");
800
- const timing = readJson(root, "init/xinyun-ai-init/templates/initialization-timing.template.json");
801
- const initResult = readJson(root, "init/xinyun-ai-init/templates/init-result.template.json");
802
- const behaviorEvidence = readJson(root, "test-scenarios/v1.12.0-behavior-evidence.json");
803
- const paths = ["hostPreflight", "initializationRecovery", "manualSessionBindings", "sharedProjectSnapshot", "initializationTiming"];
804
- const statuses = ["available", "available-with-dependency", "unavailable", "permission-denied", "unknown", "not-checked", "not-verified", "failed"];
805
- addCheck(target, "v1.12.registration", "registry", manifest.v112 && projectIndex.v112 && paths.every((key) => manifest.v112[key] === projectIndex.v112[key]) ? "pass" : "fail", "manifest/project-index.v112", "paths", "same", {manifest: manifest.v112, projectIndex: projectIndex.v112}, "v1.12 paths are registered consistently.", "Synchronize v1.12 paths.");
806
- addCheck(target, "v1.12.capabilities", "manifest", manifest.capabilities && ["hostPreflightRecovery", "manualRoleSessionBinding", "codeGraphIncrementalReuse", "sharedProjectSnapshot", "initializationTiming"].every((key) => manifest.capabilities[key] === true) ? "pass" : "fail", "manifest.template.json", "capabilities", "v1.12 flags", manifest.capabilities, "v1.12 capabilities are registered.", "Register all v1.12 capabilities.");
807
- addCheck(target, "v1.12.host-enum", "schema", JSON.stringify(host.capabilityStatusEnum) === JSON.stringify(statuses) && JSON.stringify(manifest.v112.hostCapabilityStatusEnum) === JSON.stringify(statuses) && JSON.stringify(projectIndex.v112.hostCapabilityStatusEnum) === JSON.stringify(statuses) ? "pass" : "fail", "host-preflight/manifest/project-index", "capabilityStatusEnum", statuses, {host: host.capabilityStatusEnum, manifest: manifest.v112 && manifest.v112.hostCapabilityStatusEnum, projectIndex: projectIndex.v112 && projectIndex.v112.hostCapabilityStatusEnum}, "Host capability enum is shared.", "Use one complete host capability enum.");
808
- addCheck(target, "v1.12.host-fields", "schema", host.requiredCapabilities.length === 8 && Object.values(host.capabilities).length === 8 && Object.values(host.capabilities).every((capability) => ["capabilityId", "detectionMethod", "status", "evidence", "dependencyStatus", "fallbackPlan", "usedTools", "unusedTools", "unverifiedScope", "failureReason", "checkedAt"].every((field) => Object.prototype.hasOwnProperty.call(capability, field))) ? "pass" : "fail", "host-preflight.template.json", "capabilities", "eight records with minimum fields", host.capabilities, "Host preflight evidence fields are complete.", "Complete host preflight evidence fields.");
809
- addCheck(target, "v1.12.ready-gate", "schema", host.readyGate && host.readyGate.allRequiredCapabilitiesPassed === false && host.readyGate.unknownBlocksReady === true && host.readyGate.fakeSessionIdProhibited === true ? "pass" : "fail", "host-preflight.template.json", "readyGate", "conservative default", host.readyGate, "Preflight cannot default to ready.", "Block ready until host evidence is verified.");
810
- addCheck(target, "v1.12.recovery", "schema", recovery.reuseContract && recovery.reuseContract.reuseTaskId === true && recovery.reuseContract.reuseRoleTaskIds === true && recovery.reuseContract.incrementAttempt === true && recovery.reuseContract.createDuplicateTasks === false && recovery.atomicWrite && recovery.atomicWrite.rename === true ? "pass" : "fail", "initialization-recovery.template.json", "reuse/atomicWrite", "reuse IDs, no duplicate, atomic", recovery, "Recovery contract checked.", "Restore task reuse and atomic recovery.");
811
- addCheck(target, "v1.12.manual-binding", "schema", binding.sessionId === null && binding.executionEligible === false && binding.fakeSessionIdProhibited === true && binding.evidenceRequiredFields.includes("interactionHash") ? "pass" : "fail", "manual-session-binding.template.json", "binding", "real evidence required", binding, "Manual binding gate checked.", "Require real session evidence.");
812
- addCheck(target, "v1.12.snapshot", "schema", snapshot.generatedOnce === false && snapshot.snapshotStatus === "not-checked" && snapshot.refreshTriggers.length >= 4 ? "pass" : "fail", "shared-project-snapshot.template.json", "reuse", "conservative snapshot default", snapshot, "Shared snapshot reuse contract checked.", "Record snapshot refresh triggers.");
813
- addCheck(target, "v1.12.timing", "schema", timing.stageRequiredFields.length === 10 && timing.attempt === 1 && timing.stages.length === 0 ? "pass" : "fail", "initialization-timing.template.json", "stageRequiredFields", "10 fields", timing.stageRequiredFields, "Stage timing contract checked.", "Record all timing fields.");
814
- addCheck(target, "v1.12.init-result", "schema", initResult.targetVersion === VERSION && initResult.v112 && paths.every((key) => initResult.v112[`${key}Path`] === manifest.v112[key]) && initResult.v112.duplicateTasksCreated === 0 ? "pass" : "fail", "init-result.template.json", "v112", "registered links and zero duplicates", initResult.v112, "Init-result v1.12 links checked.", "Synchronize init-result links.");
815
- const scenarioText = readText(root, "test-scenarios/v1.12.0-scenarios.md");
816
- addCheck(target, "v1.12.scenarios", "scenario", Array.from({ length: 12 }, (_, index) => 134 + index).every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("sessionId=null") ? "pass" : "fail", "test-scenarios/v1.12.0-scenarios.md", "scenarioIds", "134-145", "scanned", "v1.12 scenarios are registered.", "Add all v1.12 scenarios.");
817
- const behaviorIds = Array.from({ length: 12 }, (_, index) => 134 + index);
818
- addCheck(target, "v1.12.behavior-evidence", "evidence", behaviorEvidence.evidenceType === "not-verified" && behaviorEvidence.realAiSessionVerified === false && behaviorEvidence.publishBlocked === true && JSON.stringify(behaviorEvidence.scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(behaviorIds) && behaviorEvidence.scenarios.every((scenario) => scenario.sessionId === null && scenario.result === "not-verified" && scenario.actualOutput === "not-verified" && scenario.sensitiveScan && scenario.sensitiveScan.status === "pass" && scenario.sensitiveScan.matches.length === 0) ? "pass" : "fail", "v1.12.0-behavior-evidence.json", "realAiSessionVerified/result", "not-verified with null session IDs", behaviorEvidence, "Unavailable host evidence is honest and complete.", "Do not fabricate real session evidence.");
819
- addCheck(target, "v1.12.rule", "content", readText(root, "init/xinyun-ai-init/rules/v1.12.0-recovery.md").includes("available-with-dependency") && readText(root, "init/xinyun-ai-init/rules/v1.12.0-recovery.md").includes("sessionId=null") ? "pass" : "fail", "v1.12.0-recovery.md", "contract", "preflight and no fake IDs", "scanned", "v1.12 rule contract checked.", "Restore the v1.12 rule contract.");
820
- }
821
-
822
- function validateV1121Content(root, target) {
823
- const requiredFiles = [
824
- "init/xinyun-ai-init/rules/v1.12.1-provider-session-binding.md",
825
- "init/xinyun-ai-init/templates/provider-session-binding.template.json",
826
- "test-scenarios/v1.12.1-scenarios.md",
827
- "test-scenarios/v1.12.1-behavior-evidence.json",
828
- ];
829
- for (const file of requiredFiles) requireFile(root, target, file);
830
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
831
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
832
- const initResult = readJson(root, "init/xinyun-ai-init/templates/init-result.template.json");
833
- const binding = readJson(root, "init/xinyun-ai-init/templates/provider-session-binding.template.json");
834
- const manual = readJson(root, "init/xinyun-ai-init/templates/manual-session-binding.template.json");
835
- const evidence = readJson(root, "test-scenarios/v1.12.1-behavior-evidence.json");
836
- const statuses = ["pending", "validating", "bound", "blocked", "rejected", "released", "conflict", "recovery-required"];
837
- const modes = ["auto-created", "auto-reused", "manual", "recovery", "local-degraded"];
838
- const identityFields = ["providerSessionId", "projectRootHash", "workspaceScope", "roleId", "taskId", "title", "cwd", "source", "verifiedAt", "evidenceHash"];
839
- const interactionFields = ["sendReceipt", "receiveReceipt", "transcriptHash", "messageCount", "recordedAt", "evidenceHash"];
840
- const scenarioIds = Array.from({ length: 13 }, (_, index) => 146 + index);
841
- addCheck(target, "v1.12.1.registry", "registry", manifest.v1121 && projectIndex.v1121 && manifest.v1121.providerBindings === projectIndex.v1121.providerBindings && manifest.v1121.providerBindingTemplate === projectIndex.v1121.providerBindingTemplate ? "pass" : "fail", "manifest/project-index.v1121", "provider binding paths", "same", {manifest: manifest.v1121, projectIndex: projectIndex.v1121}, "Provider binding paths are consistent.", "Synchronize provider binding paths.");
842
- addCheck(target, "v1.12.1.schema", "schema", statuses.every((status) => binding.bindingStatusEnum.includes(status)) && modes.includes(binding.bindingMode) && identityFields.every((field) => Object.prototype.hasOwnProperty.call(binding.identityEvidence, field)) && interactionFields.every((field) => Object.prototype.hasOwnProperty.call(binding.interactionEvidence, field)) ? "pass" : "fail", "provider-session-binding.template.json", "binding schema", "complete", binding, "Provider binding schema is complete.", "Complete provider binding evidence fields and enums.");
843
- addCheck(target, "v1.12.1.gated-default", "schema", binding.providerSessionId === null && binding.bindingStatus === "pending" && binding.fakeProviderSessionIdProhibited === true && manual.providerSessionId === null && manual.executionEligible === false ? "pass" : "fail", "provider/manual binding templates", "default gate", "null/pending/false", {binding: binding, manual: manual}, "Bindings default to a conservative state.", "Do not fabricate provider session IDs.");
844
- addCheck(target, "v1.12.1.init-result", "registry", initResult.v1121 && initResult.v1121.providerSessionBindingsPath === manifest.v1121.providerBindings && initResult.v1121.providerSessionBindingTemplate === manifest.v1121.providerBindingTemplate ? "pass" : "fail", "init-result.template.json", "v1121", "registered provider binding links", initResult.v1121, "Init result links provider binding.", "Synchronize init-result provider links.");
845
- const scenarioText = readText(root, "test-scenarios/v1.12.1-scenarios.md");
846
- addCheck(target, "v1.12.1.scenarios", "scenario", scenarioIds.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("providerSessionId=null") ? "pass" : "fail", "v1.12.1-scenarios.md", "scenarioIds", "146-158", "scanned", "Provider binding scenarios are registered.", "Add all provider binding scenarios.");
847
- addCheck(target, "v1.12.1.behavior-evidence", "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) && 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) ? "pass" : "fail", "v1.12.1-behavior-evidence.json", "realAiSessionVerified/result", "not-verified with null IDs", evidence, "Unavailable host evidence is honest.", "Do not fabricate real provider session evidence.");
848
- const ruleText = readText(root, "init/xinyun-ai-init/rules/v1.12.1-provider-session-binding.md");
849
- addCheck(target, "v1.12.1.rule", "content", ["providerSessionId", "canonical", "identityEvidence", "interactionEvidence", "exclusive occupancy", "Do not fabricate"].every((term) => ruleText.includes(term)) ? "pass" : "fail", "v1.12.1-provider-session-binding.md", "contract", "canonical identity and evidence gate", "scanned", "Provider binding rule is present.", "Restore provider binding rules.");
850
- }
851
-
852
- function validateV113Content(root, target) {
853
- const requiredFiles = [
854
- "init/xinyun-ai-init/rules/v1.13.0-host-adapter.md",
855
- "init/xinyun-ai-init/templates/provider-adapter.template.json",
856
- "init/xinyun-ai-init/templates/manual-session-recovery.template.json",
857
- "init/xinyun-ai-init/templates/manual-session-binding.template.json",
858
- "init/xinyun-ai-init/templates/initialization-change-report.template.json",
859
- "test-scenarios/v1.13.0-scenarios.md",
860
- "test-scenarios/v1.13.0-behavior-evidence.json",
861
- ];
862
- for (const file of requiredFiles) requireFile(root, target, file);
863
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
864
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
865
- const initResult = readJson(root, "init/xinyun-ai-init/templates/init-result.template.json");
866
- const adapter = readJson(root, "init/xinyun-ai-init/templates/provider-adapter.template.json");
867
- const recovery = readJson(root, "init/xinyun-ai-init/templates/manual-session-recovery.template.json");
868
- const changeReport = readJson(root, "init/xinyun-ai-init/templates/initialization-change-report.template.json");
869
- const roleBinding = readJson(root, "init/xinyun-ai-init/templates/role-session-binding.template.json");
870
- const providerBinding = readJson(root, "init/xinyun-ai-init/templates/provider-session-binding.template.json");
871
- const manualBinding = readJson(root, "init/xinyun-ai-init/templates/manual-session-binding.template.json");
872
- const taskIndex = readJson(root, "init/xinyun-ai-init/templates/task-index.template.json");
873
- const assignments = readJson(root, "init/xinyun-ai-init/templates/team/assignments.json");
874
- const evidence = readJson(root, "test-scenarios/v1.13.0-behavior-evidence.json");
875
- const paths = ["providerAdapter", "manualSessionRecovery", "initializationChangeReport"];
876
- addCheck(target, "v1.13.registry", "registry", manifest.v113 && projectIndex.v113 && paths.every((key) => manifest.v113[key] === projectIndex.v113[key]) && initResult.v113 && paths.every((key) => initResult.v113[`${key}Path`] === manifest.v113[key]) ? "pass" : "fail", "manifest/project-index/init-result.v113", "paths", "same", {manifest: manifest.v113, projectIndex: projectIndex.v113, initResult: initResult.v113}, "v1.13 paths are registered consistently.", "Synchronize v1.13 control paths.");
877
- const userDecisions = ["manual-create", "defer", "redetect"];
878
- const decisionStatuses = ["not-asked", "awaiting-user", "selected", "processing", "completed", "blocked"];
879
- const decisionFields = ["decisionId", "userDecision", "actor", "source", "requiredRoleCount", "createdRoleCount", "remainingRoleIds", "decisionStatus", "decidedAt", "nextAction", "decisionEvidence"];
880
- const decisionEvidenceFields = ["decisionId", "userDecision", "actor", "source", "decidedAt", "inputHash", "evidenceHash"];
881
- const recoveryText = readText(root, "init/xinyun-ai-init/templates/manual-session-recovery.template.json");
882
- addCheck(target, "v1.13.decision-contract", "schema", 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) && decisionFields.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 && recovery.requiredRoleCount === 5 && recovery.createdRoleCount === 0 && recovery.decisionStatus === "not-asked" ? "pass" : "fail", "manual recovery/registries", "one-time user decision gate", "scanned", "User decision identity and recovery defaults checked.", "Keep decision fields synchronized and conservative.");
883
- const sessionCreationStatuses = ["not-asked", "awaiting-confirmation", "approved", "deferred", "processing", "completed", "blocked"];
884
- addCheck(target, "v1.13.task-first-session-gate", "schema", recovery.taskFirstSessionGate && initResult.v113.sessionCreationDecision && recovery.taskFirstSessionGate.mainTaskCreatedBeforeSession === true && recovery.taskFirstSessionGate.roleTasksCreatedBeforeSession === true && recovery.taskFirstSessionGate.sessionIdsRemainNullUntilDecision === true && JSON.stringify(recovery.taskFirstSessionGate.sessionCreationDecisionEnum) === JSON.stringify(["create-and-onboard", "defer"]) && JSON.stringify(recovery.taskFirstSessionGate.sessionCreationStatusEnum) === JSON.stringify(sessionCreationStatuses) && JSON.stringify(initResult.v113.sessionCreationDecision.statusEnum) === JSON.stringify(sessionCreationStatuses) && initResult.v113.sessionCreationDecision.status === "awaiting-confirmation" ? "pass" : "fail", "manual recovery/init-result", "tasks first, user approval before sessions", "scanned", "Task-first session confirmation gate checked.", "Preserve tasks before session creation and require explicit confirmation.");
885
- const capabilities = ["createRealSession", "reuseExistingSession", "sendTask", "receiveResult", "querySessionStatus", "recoverSession", "closeSession", "controlFileReadWrite"];
886
- addCheck(target, "v1.13.preflight", "schema", JSON.stringify(manifest.v113.preflightRequiredCapabilities) === JSON.stringify(capabilities) && JSON.stringify(projectIndex.v113.preflightRequiredCapabilities) === JSON.stringify(capabilities) && JSON.stringify(Object.values(adapter.operations).map((operation) => operation.operationId)) === JSON.stringify(capabilities) ? "pass" : "fail", "v1.13 adapter/registry", "requiredCapabilities", capabilities, "scanned", "All eight host operations are required before CodeGraph.", "Synchronize the host preflight capability list.");
887
- const hostCapabilities = readJson(root, "init/xinyun-ai-init/templates/host-capabilities.template.json");
888
- addCheck(target, "v1.13.host-capability-compatibility", "schema", hostCapabilities.historicalCapabilityContract && hostCapabilities.historicalCapabilityContract.requiredCount === 6 && hostCapabilities.currentProviderCapabilityContract && hostCapabilities.currentProviderCapabilityContract.requiredCount === 8 && JSON.stringify(hostCapabilities.currentProviderCapabilityContract.requiredCapabilities) === JSON.stringify(capabilities) ? "pass" : "fail", "host-capabilities.template.json", "historical/current contracts", "v1.10 six + v1.13.1 eight", hostCapabilities, "Legacy host capability records remain compatible while current provider preflight is explicit.", "Declare both the legacy six-capability contract and the current eight-capability provider contract.");
889
- const adapterStatuses = ["not-checked", "checking", "available", "available-with-dependency", "unavailable", "permission-denied", "unknown", "failed", "not-verified"];
890
- addCheck(target, "v1.13.adapter-status", "schema", JSON.stringify(adapter.statusEnum) === JSON.stringify(adapterStatuses) && adapter.fakeSessionIdProhibited === true && adapter.ordinaryThreadIdProhibited === true ? "pass" : "fail", "provider-adapter.template.json", "statusEnum/canonical ID", adapterStatuses, "scanned", "Adapter status and canonical ID restrictions checked.", "Keep provider canonical IDs and conservative statuses.");
891
- const sessionIdentityFields = ["hostThreadId", "hostSessionId", "providerSessionId", "projectSessionId", "sessionId", "orchestratorSessionId"];
892
- const requiredHostEvidence = ["create-or-reuse", "send", "receive", "query-status", "recover", "close"];
893
- const identityOk = JSON.stringify(manifest.v113.sessionIdentityFields) === JSON.stringify(sessionIdentityFields) && JSON.stringify(projectIndex.v113.sessionIdentityFields) === JSON.stringify(sessionIdentityFields) && JSON.stringify(taskIndex.sessionIdentityContract.fields) === JSON.stringify(sessionIdentityFields) && JSON.stringify(manifest.v113.requiredHostEvidence) === JSON.stringify(requiredHostEvidence) && JSON.stringify(projectIndex.v113.requiredHostEvidence) === JSON.stringify(requiredHostEvidence) && JSON.stringify(taskIndex.sessionIdentityContract.requiredHostEvidence) === JSON.stringify(requiredHostEvidence);
894
- addCheck(target, "v1.13.session-identity-contract", "schema", identityOk && manifest.v113.canonicalSessionIdentity === "providerSessionId" && projectIndex.v113.canonicalSessionIdentity === "providerSessionId" && taskIndex.sessionIdentityContract.canonicalField === "providerSessionId" && roleBinding.identityMapping.equivalenceRule.includes("sessionId equals providerSessionId") && providerBinding.identityMapping.equivalenceRule.includes("sessionId equals providerSessionId") && manualBinding.canonicalSessionIdField === "providerSessionId" && manualBinding.identityMappingRule.includes("all requiredHostEvidence") ? "pass" : "fail", "binding/task/registry templates", "canonical identity and six evidence operations", "scanned", {manifest: manifest.v113, projectIndex: projectIndex.v113, taskIndex: taskIndex.sessionIdentityContract}, "Session identity mapping is consistent.", "Synchronize canonical provider identity and evidence requirements.");
895
- addCheck(target, "v1.13.assignment-session-contract", "schema", 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") ? "pass" : "fail", "team/assignments.json", "session binding rule", "canonical provider evidence", assignments.recordContract, "Assignments enforce one canonical mapping.", "Add cross-file session identity fields and evidence rules.");
896
- const roles = ["project-owner", "project-product", "chief-engineer", "programmer", "test-reviewer"];
897
- addCheck(target, "v1.13.manual-recovery", "schema", JSON.stringify(recovery.roles.map((role) => role.roleId)) === JSON.stringify(roles) && recovery.roles.every((role) => role.providerSessionId === null && role.bindingStatus === "pending") && recovery.reuseContract.createDuplicateTasks === false && recovery.reuseContract.replaceUnverifiedSession === false ? "pass" : "fail", "manual-session-recovery.template.json", "roles/recovery", roles, "scanned", "Manual recovery is explicit and non-fabricating.", "Keep five roles pending until real evidence is supplied.");
898
- const originEnum = ["initialization-created", "initialization-updated", "pre-existing-user-change", "control-plane-only"];
899
- addCheck(target, "v1.13.change-origin", "schema", JSON.stringify(changeReport.changeOriginEnum) === JSON.stringify(originEnum) && changeReport.businessCodeChanged.value === "unknown" && changeReport.requiredChangeFields.includes("evidence") ? "pass" : "fail", "initialization-change-report.template.json", "changeOriginEnum", originEnum, "scanned", "Change origin and baseline evidence checked.", "Separate initialization and pre-existing changes.");
900
- const expectedIds = Array.from({ length: 27 }, (_, index) => 159 + index);
901
- const scenarioText = readText(root, "test-scenarios/v1.13.0-scenarios.md");
902
- addCheck(target, "v1.13.scenarios", "scenario", expectedIds.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("manual-create") && scenarioText.includes("create-and-onboard") && scenarioText.includes("decisionStatus") ? "pass" : "fail", "v1.13.0-scenarios.md", "scenarioIds", "159-185 with task-first session decisions", "scanned", "v1.13 scenarios are registered.", "Add all v1.13 decision scenarios.");
903
- const evidenceFields = ["scenarioId", "input", "expectedOutput", "actualOutput", "beforeSnapshotHash", "afterSnapshotHash", "changedFiles", "controlFilesChanged", "forbiddenOperations", "evidence", "sensitiveScan", "result", "recordHash", "recordedAt"];
904
- addCheck(target, "v1.13.behavior-evidence", "behavior", evidence.evidenceType === "not-verified" && evidence.realAiSessionVerified === false && evidence.publishBlocked === true && evidence.sessionId === null && evidence.providerSessionId === null && JSON.stringify(evidence.scenarioRequiredFields) === JSON.stringify(evidenceFields) && JSON.stringify(evidence.scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(expectedIds) && 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) ? "pass" : "fail", "test-scenarios/v1.13.0-behavior-evidence.json", "scenarios", "159-181 auditable honest not-verified", "scanned", "Real host behavior is not fabricated.", "Provide real host evidence or keep the release blocked.");
905
- const ruleText = readText(root, "init/xinyun-ai-init/rules/v1.13.0-host-adapter.md");
906
- addCheck(target, "v1.13.rule", "content", ["providerSessionId", "hostThreadId", "hostSessionId", "projectSessionId", "orchestratorSessionId", "create-or-reuse", "query-status", "Manual recovery", "manual-create", "defer", "redetect", "decisionStatus=awaiting-user", "decisionId", "pre-existing-user-change", "No provider login/install"].every((term) => ruleText.includes(term)) ? "pass" : "fail", "v1.13.0-host-adapter.md", "contract", "adapter/mapping/recovery/decision/scope", "scanned", "v1.13 rule contract checked.", "Restore v1.13 host adapter identity and decision rules.");
907
- }
908
-
909
- function validateV114Content(root, target) {
910
- const requiredFiles = [
911
- "init/xinyun-ai-init/rules/v1.14.0-agent-core.md",
912
- "init/xinyun-ai-init/templates/agent-profile.template.json",
913
- "init/xinyun-ai-init/templates/agent-capabilities.template.json",
914
- "init/xinyun-ai-init/templates/takeover-gate.template.json",
915
- "init/xinyun-ai-init/templates/orchestrator.template.json",
916
- "init/xinyun-ai-init/templates/task-graph.template.json",
917
- "init/xinyun-ai-init/templates/handoff.template.json",
918
- "init/xinyun-ai-init/templates/final-delivery.template.json",
919
- "test-scenarios/v1.14.0-scenarios.md",
920
- "test-scenarios/v1.14.0-behavior-evidence.json",
921
- ];
922
- for (const file of requiredFiles) requireFile(root, target, file);
923
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
924
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
925
- const initResult = readJson(root, "init/xinyun-ai-init/templates/init-result.template.json");
926
- const profile = readJson(root, "init/xinyun-ai-init/templates/agent-profile.template.json");
927
- const capabilities = readJson(root, "init/xinyun-ai-init/templates/agent-capabilities.template.json");
928
- const takeover = readJson(root, "init/xinyun-ai-init/templates/takeover-gate.template.json");
929
- const orchestrator = readJson(root, "init/xinyun-ai-init/templates/orchestrator.template.json");
930
- const graph = readJson(root, "init/xinyun-ai-init/templates/task-graph.template.json");
931
- const evidence = readJson(root, "test-scenarios/v1.14.0-behavior-evidence.json");
932
- const paths = ["profile", "capabilities", "takeoverGate", "orchestrator", "taskGraph", "handoffsDirectory", "finalDelivery"];
933
- addCheck(target, "v1.14.registration", "registry", manifest.agentCore && projectIndex.agentCore && paths.every((key) => manifest.agentCore[key] === projectIndex.agentCore[key]) && manifest.v114 && projectIndex.v114 && initResult.v114 && initResult.agentCore && initResult.agentCore.profilePath === manifest.agentCore.profile ? "pass" : "fail", "manifest/project-index/init-result.v114", "paths", "same", {manifest: manifest.agentCore, projectIndex: projectIndex.agentCore, initResult: initResult.agentCore}, "v1.14 paths are registered consistently.", "Synchronize v1.14 control-plane paths.");
934
- const profileFields = ["agentId", "name", "version", "projectIdentity", "serviceGoal", "configuredRoles", "supportedStacks", "supportedTools", "allowedOperations", "forbiddenOperations", "readyPrerequisites", "capabilityStatus"];
935
- addCheck(target, "v1.14.agent-profile", "schema", profileFields.every((field) => Object.prototype.hasOwnProperty.call(profile, field)) && profile.configuredRoles.length === 5 && profile.capabilityStatus === "manual-required" ? "pass" : "fail", "agent-profile.template.json", "profile fields", "complete and conservative", profile, "Agent identity and service scope are declared.", "Complete the agent profile and keep status conservative.");
936
- addCheck(target, "v1.14.capabilities", "schema", capabilities.aggregateStatus === "manual-required" && capabilities.capabilities.every((capability) => capability.required === true && capability.evidence && capability.fallbackPlan && capability.unverifiedScope) ? "pass" : "fail", "agent-capabilities.template.json", "aggregateStatus/evidence", "manual-required with evidence", capabilities, "Capability status and fallback evidence are declared.", "Do not mark unknown capabilities ready.");
937
- addCheck(target, "v1.14.takeover-gate", "schema", takeover.status === "blocked" && takeover.executionEligible === false && takeover.requiredGates.length >= 12 && takeover.blockedReasons.includes("required-role-session-not-created") ? "pass" : "fail", "takeover-gate.template.json", "status/gates", "blocked until evidence", takeover, "Takeover gate is conservative.", "Keep missing evidence blocked.");
938
- addCheck(target, "v1.14.orchestrator-task-graph", "schema", orchestrator.orchestratorSessionId === null && orchestrator.responsibilities.length >= 8 && graph.acyclic === true && graph.taskStatusLabelMap["waiting-review"] === "待审查" ? "pass" : "fail", "orchestrator/task-graph", "identity/status map", "independent and acyclic", {orchestrator, graph}, "Orchestrator and task graph are registered.", "Preserve the independent orchestrator and dependency graph.");
939
- addCheck(target, "v1.14.evidence", "behavior", 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]) && evidence.scenarios.length === 20 ? "pass" : "fail", "v1.14.0-behavior-evidence.json", "scenarioRange/evidenceType", "186-205 local-degraded", evidence, "Local-degraded evidence is explicitly non-ready and provider-safe.", "Keep localSessionId separate from providerSessionId.");
940
- const scenarioText = readText(root, "test-scenarios/v1.14.0-scenarios.md");
941
- addCheck(target, "v1.14.scenarios", "scenario", Array.from({length: 20}, (_, index) => 186 + index).every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("conflict") && scenarioText.includes("beforeSnapshotHash") ? "pass" : "fail", "v1.14.0-scenarios.md", "scenarioIds", "186-205", "scanned", "v1.14 scenarios are registered.", "Add all v1.14 agent-core scenarios.");
942
- const v114EvidenceFields = ["scenarioId", "input", "expectedOutput", "actualOutput", "beforeSnapshotHash", "afterSnapshotHash", "changedFiles", "controlFilesChanged", "forbiddenOperations", "evidence", "sensitiveScan", "result", "recordHash", "recordedAt"];
943
- addCheck(target, "v1.14.evidence-fields", "behavior", JSON.stringify(evidence.scenarioRequiredFields) === JSON.stringify([...v114EvidenceFields, "localSessionId"]) && evidence.scenarios.every((scenario, index) => [...v114EvidenceFields, "localSessionId"].every((field) => Object.prototype.hasOwnProperty.call(scenario, field)) && scenario.scenarioId === 186 + index && 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) ? "pass" : "fail", "v1.14.0-behavior-evidence.json", "scenario fields", "complete auditable local-degraded records", evidence.scenarios, "Every v1.14 scenario has an auditable local record without a provider ID.", "Complete local evidence and keep providerSessionId null.");
944
- const ruleText = readText(root, "init/xinyun-ai-init/rules/v1.14.0-agent-core.md");
945
- addCheck(target, "v1.14.rule", "content", ["Agent identity", "Takeover gate", "Orchestrator", "Shared facts", "Final delivery", "providerSessionId", "localSessionId", "local-degraded"].every((term) => ruleText.includes(term)) ? "pass" : "fail", "v1.14.0-agent-core.md", "contract", "agent/takeover/task/handoff/delivery/local fallback", "scanned", "v1.14 rule contract checked.", "Restore v1.14 agent-core rules and local fallback contract.");
946
- }
947
-
948
- function validateV115Content(root, target) {
949
- const requiredFiles = [
950
- "init/xinyun-ai-init/rules/v1.15.0-session-binding.md",
951
- "init/xinyun-ai-init/templates/session-binding.template.json",
952
- "test-scenarios/v1.15.0-scenarios.md",
953
- "test-scenarios/v1.15.0-behavior-evidence.json",
954
- ];
955
- for (const file of requiredFiles) requireFile(root, target, file);
956
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
957
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
958
- const initResult = readJson(root, "init/xinyun-ai-init/templates/init-result.template.json");
959
- const binding = readJson(root, "init/xinyun-ai-init/templates/session-binding.template.json");
960
- const evidence = readJson(root, "test-scenarios/v1.15.0-behavior-evidence.json");
961
- const fields = ["sessionId", "sessionRefType", "sessionRef", "hostId", "provider", "projectRootHash", "workspaceScope", "repositoryScope", "workstream", "roleId", "taskId", "title", "cwd", "identityEvidence", "interactionEvidence", "bindingStatus", "bindingMode", "createdAt", "updatedAt"];
962
- const evidenceCategories = ["create-or-reuse", "send", "receive", "query-status", "recover", "close", "control-file-read-write"];
963
- const registry = manifest.v115 && projectIndex.v115 && initResult.v115 && manifest.v115.sessionBindingTemplate === projectIndex.v115.sessionBindingTemplate && manifest.v115.sessionBindingTemplate === initResult.v115.sessionBindingTemplate && manifest.v115.canonicalControlPlaneId === "sessionId" && projectIndex.v115.canonicalControlPlaneId === "sessionId" && initResult.v115.canonicalControlPlaneId === "sessionId";
964
- addCheck(target, "v1.15.registry", "registry", registry ? "pass" : "fail", "manifest/project-index/init-result.v115", "session binding paths", "same adapter-neutral contract", {manifest: manifest.v115, projectIndex: projectIndex.v115, initResult: initResult.v115}, "v1.15 adapter-neutral paths are registered consistently.", "Synchronize v1.15 session binding registry paths.");
965
- addCheck(target, "v1.15.binding-schema", "schema", fields.every((field) => Object.prototype.hasOwnProperty.call(binding, field)) && JSON.stringify(binding.requiredEvidenceCategories) === JSON.stringify(evidenceCategories) && binding.bindingStatus === "pending" && binding.executionEligible === false ? "pass" : "fail", "session-binding.template.json", "fields/evidence/default", "complete pending contract", binding, "Adapter-neutral session binding schema is conservative and complete.", "Keep the seven evidence categories and non-ready default.");
966
- const ruleText = readText(root, "init/xinyun-ai-init/rules/v1.15.0-session-binding.md");
967
- addCheck(target, "v1.15.rule", "content", ["adapter-neutral", "sessionRefType", "host-thread", "provider-session", "manual-reference", "local-session", "seven evidence", "providerSessionId", "Cross-project"].every((term) => ruleText.includes(term)) ? "pass" : "fail", "v1.15.0-session-binding.md", "contract", "adapter-neutral identity and evidence gate", "scanned", "v1.15 session binding rule is present.", "Restore the adapter-neutral session binding rule.");
968
- const scenarioText = readText(root, "test-scenarios/v1.15.0-scenarios.md");
969
- const ids = Array.from({length: 18}, (_, index) => 206 + index);
970
- addCheck(target, "v1.15.scenarios", "scenario", ids.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("host-thread") && scenarioText.includes("跨项目") ? "pass" : "fail", "v1.15.0-scenarios.md", "scenarioIds", "206-223", "scanned", "v1.15 scenarios cover positive and negative binding plus collaboration gates.", "Add all v1.15 scenarios.");
971
- const realEvidenceCategories = new Set((evidence.interactionEvidence || []).map((record) => record.operation));
972
- const v115PlannedEvidence = evidence.evidenceType === "not-verified" && evidence.realAiSessionVerified === false && evidence.publishBlocked === true && evidence.scenarios.every((scenario) => scenario.actualOutput === "not-verified" && scenario.result === "not-verified");
973
- const v115RealSessionEvidence = evidence.evidenceType === "real-session" && evidence.realAiSessionVerified === true && evidence.sessionRefType === "host-thread" && typeof evidence.sessionRef === "string" && evidence.hostId === "local" && evidence.readyEligible === true && evidence.scenarios.some((scenario) => scenario.scenarioId === 206 && scenario.result === "real-passed" && scenario.sessionRef === evidence.sessionRef) && evidence.requiredHostEvidence.every((operation) => realEvidenceCategories.has(operation)) && evidence.scenarios.every((scenario) => scenario.result === "real-passed" || scenario.result === "real-negative-passed" || scenario.result === "contract-passed");
974
- addCheck(target, "v1.15.evidence", "behavior", 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 && Array.isArray(scenario.evidence)) && (v115PlannedEvidence || v115RealSessionEvidence) ? "pass" : "fail", "v1.15.0-behavior-evidence.json", "evidence", "planned or real host-thread evidence", evidence, "v1.15 evidence records either an honest planned gate or auditable real host-thread interaction evidence.", "Keep real session references and all seven operation records auditable; do not fabricate untested scenarios.");
975
- }
976
-
977
- function validateV116Content(root, target) {
978
- const requiredFiles = [
979
- "init/xinyun-ai-init/rules/v1.16.0-capability-efficiency.md",
980
- "init/xinyun-ai-init/templates/skill-runtime-route.template.json",
981
- "init/xinyun-ai-init/templates/skill-run-record.template.json",
982
- "init/xinyun-ai-init/templates/codegraph-incremental-record.template.json",
983
- "init/xinyun-ai-init/templates/local-query-index.template.json",
984
- "init/xinyun-ai-init/templates/performance-metrics.template.json",
985
- "test-scenarios/v1.16.0-scenarios.md",
986
- "test-scenarios/v1.16.0-behavior-evidence.json",
987
- "scripts/collect-v1.16-evidence.js",
988
- ];
989
- for (const file of requiredFiles) requireFile(root, target, file);
990
-
991
- const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
992
- const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
993
- const initResult = readJson(root, "init/xinyun-ai-init/templates/init-result.template.json");
994
- const route = readJson(root, "init/xinyun-ai-init/templates/skill-runtime-route.template.json");
995
- const run = readJson(root, "init/xinyun-ai-init/templates/skill-run-record.template.json");
996
- const graph = readJson(root, "init/xinyun-ai-init/templates/codegraph-incremental-record.template.json");
997
- const index = readJson(root, "init/xinyun-ai-init/templates/local-query-index.template.json");
998
- const metrics = readJson(root, "init/xinyun-ai-init/templates/performance-metrics.template.json");
999
- const evidence = readJson(root, "test-scenarios/v1.16.0-behavior-evidence.json");
1000
- const ruleText = readText(root, "init/xinyun-ai-init/rules/v1.16.0-capability-efficiency.md");
1001
- const scenarioText = readText(root, "test-scenarios/v1.16.0-scenarios.md");
1002
- const expectedIds = Array.from({ length: 15 }, (_, index) => index + 301);
1003
- const routeFields = ["selected", "rejected", "fallback", "blocked", "selectionOrder", "registryDigest"];
1004
- const runFields = ["skillRunId", "skillId", "roleId", "taskId", "routeReason", "usedTools", "unusedTools", "fallbackReason", "evidence", "unverifiedScope"];
1005
- const graphFields = ["recordId", "projectRootHash", "indexIdentity", "sourceHash", "changedFiles", "unchangedFiles", "failedFiles", "unverifiedScope", "oldHealthyIndexPreserved"];
1006
- const indexFields = ["sourceHash", "builtAt", "indexVersion", "coverage", "stale", "factSourcePolicy", "queryBudget"];
1007
- const 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;
1008
- addCheck(target, "v1.16.registry", "registry", registry ? "pass" : "fail", "manifest/project-index/init-result.v116", "runtime paths", "same v1.16 paths", {manifest: manifest.v116, projectIndex: projectIndex.v116, initResult: initResult.v116}, "v1.16 runtime paths are registered consistently.", "Synchronize v1.16 control-plane paths.");
1009
- addCheck(target, "v1.16.skill-route-schema", "schema", routeFields.every((field) => Object.prototype.hasOwnProperty.call(route, field)) && route.selectionOrder.length === 4 ? "pass" : "fail", "skill-runtime-route.template.json", "route fields", "selection and decision fields", route, "Runtime Skill route schema is complete.", "Keep deterministic route decisions and provenance.");
1010
- addCheck(target, "v1.16.skill-run-schema", "schema", runFields.every((field) => Object.prototype.hasOwnProperty.call(run, field)) && run.status === "pending" ? "pass" : "fail", "skill-run-record.template.json", "run fields", "minimum run record", run, "Skill execution record is conservative by default.", "Keep unverified scope and fallback evidence.");
1011
- addCheck(target, "v1.16.codegraph-schema", "schema", graphFields.every((field) => Object.prototype.hasOwnProperty.call(graph, field)) && graph.oldHealthyIndexPreserved === true && graph.status === "unknown" ? "pass" : "fail", "codegraph-incremental-record.template.json", "incremental fields", "failure-safe record", graph, "Incremental CodeGraph record preserves a healthy prior index.", "Do not claim an update after a failed increment.");
1012
- addCheck(target, "v1.16.query-index-schema", "schema", indexFields.every((field) => Object.prototype.hasOwnProperty.call(index, field)) && index.factSourcePolicy.includes("authoritative") && index.sqlitePolicy.includes("optional") ? "pass" : "fail", "local-query-index.template.json", "index fields", "derived index contract", index, "Local query index is derived and rebuildable.", "Keep JSON/Markdown as the fact source.");
1013
- addCheck(target, "v1.16.performance-schema", "schema", metrics.fixedMaterializationTargetMs === 5000 && metrics.stageRequiredFields.includes("cacheHit") && Object.prototype.hasOwnProperty.call(metrics.metrics, "controlPlaneReads") ? "pass" : "fail", "performance-metrics.template.json", "metrics", "repeatable stage metrics", metrics, "Efficiency metrics include cache, reads and baseline fields.", "Record relative stage evidence.");
1014
- addCheck(target, "v1.16.rule", "content", ["Runtime Skill routing", "Incremental CodeGraph", "local query index", "SQLite is optional", "providerSessionId", "5 seconds", "partial", "blocked"].every((term) => ruleText.includes(term)) ? "pass" : "fail", "v1.16.0-capability-efficiency.md", "contract", "routing/index/efficiency safety rules", "scanned", "v1.16 rules cover the required scope and exclusions.", "Restore v1.16 capability and efficiency rules.");
1015
- addCheck(target, "v1.16.scenarios", "scenario", expectedIds.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("three batches") ? "pass" : "fail", "v1.16.0-scenarios.md", "scenarioIds", "301-315", "scanned", "v1.16 scenarios cover A/B/C independently.", "Add all v1.16 scenarios.");
1016
- const scenarioShape = evidence.scenarios.every((scenario, index) => scenario.scenarioId === expectedIds[index] && (scenario.result === "contract-passed" || scenario.result === "real-passed") && Array.isArray(scenario.evidence) && Array.isArray(scenario.unverifiedScope) && (scenario.result !== "real-passed" || scenario.sessionRef === evidence.sessionRef));
1017
- const expectedRealBehavior = ["skill-route", "codegraph-cache", "incremental-update", "query-index", "efficiency-metrics"];
1018
- const plannedEvidence = evidence.evidenceType === "contract-regression" && evidence.realAiSessionVerified === false && evidence.publishBlocked === true && evidence.readyEligible === false;
1019
- 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;
1020
- addCheck(target, "v1.16.evidence", "behavior", evidence.version === "1.16.0" && JSON.stringify(evidence.scenarioRange) === JSON.stringify([301, 315]) && evidence.scenarios.length === 15 && scenarioShape && (plannedEvidence || realHostEvidence) ? "pass" : "fail", "v1.16.0-behavior-evidence.json", "evidence", "contract evidence or recorded real host probe", evidence, "v1.16 evidence separates contract tests from the recorded real host scope.", "Keep the release blocked unless the real host probe is complete and auditable.");
1021
- }
1022
-
1023
- function validateJsonFiles(root, target) {
1024
- const jsonFiles = [
1025
- "package.json",
1026
- "init/xinyun-ai-init/version.json",
1027
- "init/xinyun-ai-init/templates/manifest.template.json",
1028
- "init/xinyun-ai-init/templates/project-index.template.json",
1029
- "init/xinyun-ai-init/templates/framework-profile.template.json",
1030
- "init/xinyun-ai-init/templates/html-migration-record.template.json",
1031
- "init/xinyun-ai-init/templates/task-index.template.json",
1032
- "init/xinyun-ai-init/templates/archive-transaction.template.json",
1033
- "init/xinyun-ai-init/templates/role-session-binding.template.json",
1034
- "init/xinyun-ai-init/templates/session-binding.template.json",
1035
- "init/xinyun-ai-init/templates/project-identity.template.json",
1036
- "init/xinyun-ai-init/templates/session-candidates.template.json",
1037
- "init/xinyun-ai-init/templates/technical-landscape.template.json",
1038
- "init/xinyun-ai-init/templates/requirement-packet.template.json",
1039
- "init/xinyun-ai-init/templates/technical-impact-packet.template.json",
1040
- "init/xinyun-ai-init/templates/database-authorization.template.json",
1041
- "init/xinyun-ai-init/templates/host-preflight.template.json",
1042
- "init/xinyun-ai-init/templates/initialization-recovery.template.json",
1043
- "init/xinyun-ai-init/templates/manual-session-binding.template.json",
1044
- "init/xinyun-ai-init/templates/shared-project-snapshot.template.json",
1045
- "init/xinyun-ai-init/templates/initialization-timing.template.json",
1046
- "init/xinyun-ai-init/templates/provider-adapter.template.json",
1047
- "init/xinyun-ai-init/templates/manual-session-recovery.template.json",
1048
- "init/xinyun-ai-init/templates/initialization-change-report.template.json",
1049
- "init/xinyun-ai-init/templates/agent-profile.template.json",
1050
- "init/xinyun-ai-init/templates/agent-capabilities.template.json",
1051
- "init/xinyun-ai-init/templates/takeover-gate.template.json",
1052
- "init/xinyun-ai-init/templates/orchestrator.template.json",
1053
- "init/xinyun-ai-init/templates/task-graph.template.json",
1054
- "init/xinyun-ai-init/templates/handoff.template.json",
1055
- "init/xinyun-ai-init/templates/final-delivery.template.json",
1056
- "test-scenarios/v1.14.0-behavior-evidence.json",
1057
- "test-scenarios/v1.15.0-behavior-evidence.json",
1058
- "init/xinyun-ai-init/templates/skill-runtime-route.template.json",
1059
- "init/xinyun-ai-init/templates/skill-run-record.template.json",
1060
- "init/xinyun-ai-init/templates/codegraph-incremental-record.template.json",
1061
- "init/xinyun-ai-init/templates/local-query-index.template.json",
1062
- "init/xinyun-ai-init/templates/performance-metrics.template.json",
1063
- "test-scenarios/v1.16.0-behavior-evidence.json",
1064
- ];
1065
-
1066
- for (const file of jsonFiles) {
1067
- try {
1068
- readJson(root, file);
1069
- addCheck(target, "json.parse", "json", "pass", file, null, "parseable JSON", "parseable JSON", "JSON file is parseable.", null);
1070
- } catch (error) {
1071
- addCheck(target, "json.parse", "json", "fail", file, null, "parseable JSON", error.message, "JSON file is not parseable.", "Fix JSON syntax.");
1072
- }
1073
- }
1074
- }
1075
-
1076
- function validateRoot(root, target, isTarball = false) {
1077
- requireFile(root, target, "package.json");
1078
- requireFile(root, target, "README.md");
1079
- requireFile(root, target, "init/xinyun-ai-init/README.md");
1080
- requireFile(root, target, "init/xinyun-ai-init/templates/AGENTS.template.md");
1081
- requireFile(root, target, "init/xinyun-ai-init/templates/core-rules.template.md");
1082
- requireFile(root, target, "scripts/verify-init-package.js");
1083
- requireFile(root, target, "scripts/verify-rules-package.js");
1084
- validateVersion(root, target);
1085
- validatePackageFiles(root, target, isTarball);
1086
- validateTarballSecurityContract(root, target);
1087
- validateRegistries(root, target);
1088
- validateV17Content(root, target);
1089
- validateV171Content(root, target);
1090
- validateV172Content(root, target);
1091
- validateV173Content(root, target);
1092
- validateV18Content(root, target);
1093
- validateV19Content(root, target);
1094
- validateV110Content(root, target);
1095
- validateV111Content(root, target);
1096
- validateV112Content(root, target);
1097
- validateV1121Content(root, target);
1098
- validateV113Content(root, target);
1099
- validateV114Content(root, target);
1100
- validateV115Content(root, target);
1101
- validateV116Content(root, target);
1102
- validateJsonFiles(root, target);
1103
- }
1104
-
1105
- function runTar(args, tarballPath) {
1106
- const result = spawnSync("tar", [...args, tarballPath], { encoding: "utf8" });
1107
- if (result.status !== 0) {
1108
- throw Object.assign(new Error(result.stderr || result.stdout || "tar command failed"), { exitCode: 2 });
1109
- }
1110
- return result.stdout || "";
1111
- }
1112
-
1113
- function validateTarEntryName(rawName) {
1114
- const name = String(rawName || "");
1115
- if (!name) return "empty entry name";
1116
- if (name.includes("\\")) return "backslash path separator is not allowed";
1117
- if (name.startsWith("/") || name.startsWith("\\")) return "absolute path is not allowed";
1118
- if (/^[A-Za-z]:/.test(name)) return "Windows drive absolute path is not allowed";
1119
- if (name.startsWith("//")) return "UNC absolute path is not allowed";
1120
-
1121
- const parts = name.split("/");
1122
- if (parts.some((part) => part === "..")) return "path traversal is not allowed";
1123
- if (parts.some((part) => part === ".")) return "dot path segment is not allowed";
1124
- if (parts.some((part, index) => part === "" && index !== parts.length - 1)) return "empty path segment is not allowed";
1125
- if (!(name === "package" || name === "package/" || name.startsWith("package/"))) return "entry must stay under package/";
1126
- return null;
1127
- }
1128
-
1129
- function validateTarEntryTypes(tarballPath) {
1130
- const verbose = runTar(["-tvf"], tarballPath);
1131
- for (const line of verbose.split(/\r?\n/).filter(Boolean)) {
1132
- const type = line[0];
1133
- if (type === "l") return "symbolic link entries are not allowed";
1134
- if (type === "h") return "hard link entries are not allowed";
1135
- if (!"-d".includes(type)) return `unsupported tar entry type '${type}' is not allowed`;
1136
- }
1137
- return null;
1138
- }
1139
-
1140
- function assertExtractPathInsideRoot(root, candidatePath) {
1141
- const relative = path.relative(root, candidatePath);
1142
- return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
1143
- }
1144
-
1145
- function verifyExtractedTree(root) {
1146
- const pending = [root];
1147
- while (pending.length > 0) {
1148
- const current = pending.pop();
1149
- const stat = fs.lstatSync(current);
1150
- if (stat.isSymbolicLink()) return `symbolic link extracted: ${path.relative(root, current)}`;
1151
- if (stat.nlink > 1 && stat.isFile()) return `hard link extracted: ${path.relative(root, current)}`;
1152
- if (stat.isDirectory()) {
1153
- for (const child of fs.readdirSync(current)) {
1154
- const childPath = path.join(current, child);
1155
- if (!assertExtractPathInsideRoot(root, childPath)) return `path escaped extraction root: ${child}`;
1156
- pending.push(childPath);
1157
- }
1158
- }
1159
- }
1160
- return null;
1161
- }
1162
-
1163
- function extractTarball(tarballPath) {
1164
- if (!fs.existsSync(tarballPath)) throw Object.assign(new Error(`Tarball does not exist: ${tarballPath}`), { exitCode: 2 });
1165
- if (!fs.statSync(tarballPath).isFile()) throw Object.assign(new Error(`Tarball is not a file: ${tarballPath}`), { exitCode: 2 });
1166
-
1167
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "xinyun-ai-verify-rules-"));
1168
- try {
1169
- const typeError = validateTarEntryTypes(tarballPath);
1170
- if (typeError) throw Object.assign(new Error(`Unsafe tarball entry: ${typeError}`), { exitCode: 2 });
1171
-
1172
- const listedNames = runTar(["-tf"], tarballPath).split(/\r?\n/).filter(Boolean);
1173
- if (listedNames.length === 0) throw Object.assign(new Error("Tarball has no entries"), { exitCode: 2 });
1174
-
1175
- for (const entry of listedNames) {
1176
- const nameError = validateTarEntryName(entry);
1177
- if (nameError) throw Object.assign(new Error(`Unsafe tarball entry '${entry}': ${nameError}`), { exitCode: 2 });
1178
- }
1179
-
1180
- for (const entry of listedNames) {
1181
- const targetPath = path.join(tempDir, ...entry.split("/"));
1182
- if (!assertExtractPathInsideRoot(tempDir, targetPath)) {
1183
- throw Object.assign(new Error(`Unsafe tarball entry '${entry}': path traversal after resolution`), { exitCode: 2 });
1184
- }
1185
- const dir = entry.endsWith("/") ? targetPath : path.dirname(targetPath);
1186
- fs.mkdirSync(dir, { recursive: true });
1187
- }
1188
-
1189
- const tar = spawnSync("tar", ["-xf", tarballPath, "-C", tempDir], { encoding: "utf8" });
1190
- if (tar.status !== 0) {
1191
- throw Object.assign(new Error(`Failed to extract tarball: ${tar.stderr || tar.stdout || "unknown error"}`), { exitCode: 2 });
1192
- }
1193
-
1194
- const treeError = verifyExtractedTree(tempDir);
1195
- if (treeError) throw Object.assign(new Error(`Unsafe tarball extraction: ${treeError}`), { exitCode: 2 });
1196
-
1197
- const packageRoot = path.join(tempDir, "package");
1198
- if (!fs.existsSync(packageRoot)) {
1199
- throw Object.assign(new Error("Tarball extraction did not produce package/ root"), { exitCode: 2 });
1200
- }
1201
- return { tempDir, packageRoot };
1202
- } catch (error) {
1203
- fs.rmSync(tempDir, { recursive: true, force: true });
1204
- throw error;
1205
- }
1206
- }
1207
-
1208
- function overallStatus() {
1209
- if (checks.some((check) => check.status === "error")) return "error";
1210
- if (checks.some((check) => check.status === "fail")) return "fail";
1211
- if (checks.some((check) => check.status === "warn")) return "warn";
1212
- return "pass";
1213
- }
1214
-
1215
- function printHuman(result) {
1216
- for (const check of result.checks) {
1217
- const location = check.path ? ` ${check.path}` : "";
1218
- console.log(`[${check.status.toUpperCase()}] ${check.checkId}${location} - ${check.message}`);
1219
- if (check.status !== "pass" && check.suggestion) console.log(` suggestion: ${check.suggestion}`);
1220
- }
1221
- console.log("");
1222
- console.log(`[xinyun-ai-init verify:rules] status=${result.status}; pass=${result.summary.pass}; warn=${result.summary.warn}; fail=${result.summary.fail}; error=${result.summary.error}`);
1223
- }
1224
-
1225
- function printHelp() {
1226
- console.log("Usage: npm run verify:rules -- [--source-root <path>] [--tarball <path>] [--json]");
1227
- console.log("Read-only rule package consistency verification. It never repairs files, installs dependencies, writes Git state, or changes business code.");
1228
- }
1229
-
1230
- function buildResult(options, status, tarballStatus) {
1231
- return {
1232
- schemaVersion: 1,
1233
- status,
1234
- sourceRoot: options ? options.sourceRoot : null,
1235
- tarball: { path: options ? options.tarball : null, status: tarballStatus },
1236
- checks,
1237
- summary: {
1238
- pass: checks.filter((check) => check.status === "pass").length,
1239
- warn: checks.filter((check) => check.status === "warn").length,
1240
- fail: checks.filter((check) => check.status === "fail").length,
1241
- error: checks.filter((check) => check.status === "error").length,
1242
- },
1243
- checkedAt: new Date().toISOString(),
1244
- };
1245
- }
1246
-
1247
- function main() {
1248
- let options;
1249
- let extracted = null;
1250
- try {
1251
- options = parseArgs(process.argv.slice(2));
1252
- if (options.help) {
1253
- printHelp();
1254
- process.exit(0);
1255
- }
1256
- if (!fs.existsSync(options.sourceRoot) || !fs.statSync(options.sourceRoot).isDirectory()) {
1257
- throw Object.assign(new Error(`Source root is not a directory: ${options.sourceRoot}`), { exitCode: 2 });
1258
- }
1259
-
1260
- validateRoot(options.sourceRoot, "source", false);
1261
- let tarballStatus = "not-run";
1262
- if (options.tarball) {
1263
- extracted = extractTarball(options.tarball);
1264
- tarballStatus = "checked";
1265
- validateRoot(extracted.packageRoot, "tarball", true);
1266
- }
1267
-
1268
- const result = buildResult(options, overallStatus(), tarballStatus);
1269
- if (options.json) console.log(JSON.stringify(result, null, 2));
1270
- else printHuman(result);
1271
- if (result.status === "fail") process.exit(1);
1272
- if (result.status === "error") process.exit(2);
1273
- process.exit(0);
1274
- } catch (error) {
1275
- checks.length = 0;
1276
- addCheck("command", "runtime.error", "runtime", "error", null, null, "successful verify:rules execution", error.message, error.message, "Check command arguments, file permissions, and tarball readability.");
1277
- const result = buildResult(options, "error", options && options.tarball ? "error" : "not-run");
1278
- if (options && options.json) console.log(JSON.stringify(result, null, 2));
1279
- else printHuman(result);
1280
- process.exit(error.exitCode || 2);
1281
- } finally {
1282
- if (extracted && extracted.tempDir) fs.rmSync(extracted.tempDir, { recursive: true, force: true });
1283
- }
1284
- }
1285
-
1286
- main();
1287
-