@pm_zhousl/xinyun-ai-init 1.10.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/init/xinyun-ai-init/README.md +2 -2
- package/init/xinyun-ai-init/templates/init-result.template.json +1 -1
- package/init/xinyun-ai-init/templates/managed-baseline.template.json +2 -2
- package/init/xinyun-ai-init/templates/manifest.template.json +2 -2
- package/init/xinyun-ai-init/templates/requirement-packet.template.json +1 -1
- package/init/xinyun-ai-init/templates/role-session-binding.template.json +2 -2
- package/init/xinyun-ai-init/templates/technical-impact-packet.template.json +1 -1
- package/init/xinyun-ai-init/templates/technical-landscape.template.json +1 -1
- package/init/xinyun-ai-init/version.json +1 -1
- package/package.json +2 -1
- package/scripts/collect-v1.10-evidence.js +159 -0
- package/scripts/verify-init-package.js +18 -8
- package/scripts/verify-rules-package.js +9 -3
- package/test-scenarios/README.md +2 -2
- package/test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/README.md +23 -0
- package/test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/after/project-status.json +7 -0
- package/test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/before/project-status.json +7 -0
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ npx --yes @pm_zhousl/xinyun-ai-init@latest --force
|
|
|
24
24
|
npm run verify:init
|
|
25
25
|
npm run verify:rules
|
|
26
26
|
npm run verify:rules -- --json
|
|
27
|
-
npm run verify:rules -- --tarball ./pm_zhousl-xinyun-ai-init-1.10.
|
|
27
|
+
npm run verify:rules -- --tarball ./pm_zhousl-xinyun-ai-init-1.10.1.tgz
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
`verify:rules` 为只读规则包一致性检查,不自动修复、不安装依赖、不修改 Git 或业务代码。
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
本目录是“欣芸技术开发 Agent 流”的初始化包,负责把完整 AI 执行要求下发到目标项目。
|
|
4
4
|
|
|
5
|
-
当前规则版本:`1.10.
|
|
5
|
+
当前规则版本:`1.10.1`。
|
|
6
6
|
|
|
7
7
|
## Codex 一句话入口
|
|
8
8
|
|
|
@@ -19,7 +19,7 @@ npx --yes @pm_zhousl/xinyun-ai-init@latest --force
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
v1.7.2 fixed task contract keys: `taskKind=initialization-main`, `taskKind=initialization-record`, `taskKind=role-execution`.
|
|
22
|
-
v1.7.3 fixed Codex role session creation compatibility fields: `provider=codex`, `sessionStatus=pending/creating/created/onboarding/ready/blocked/failed/closed`, and legacy creation index `{taskId,roleId,provider,targetVersion}`. v1.10.
|
|
22
|
+
v1.7.3 fixed Codex role session creation compatibility fields: `provider=codex`, `sessionStatus=pending/creating/created/onboarding/ready/blocked/failed/closed`, and legacy creation index `{taskId,roleId,provider,targetVersion}`. v1.10.x takeover gates are authoritative for project readiness.
|
|
23
23
|
v1.7.3 Codex role session orchestration is host-level only; CLI still only creates `xinyun-ai-init/`.
|
|
24
24
|
|
|
25
25
|
执行上面的命令后,会生成 `xinyun-ai-init/`。随后让 AI 读取 `xinyun-ai-init/README.md` 即可。
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"hashAlgorithm": "sha256",
|
|
4
4
|
"contentEncoding": "utf8-normalized",
|
|
5
5
|
"managedBy": "@pm_zhousl/xinyun-ai-init",
|
|
6
|
-
"lastAppliedVersion": "1.10.
|
|
6
|
+
"lastAppliedVersion": "1.10.1",
|
|
7
7
|
"files": [
|
|
8
8
|
{
|
|
9
9
|
"path": "xinyun-ai/rules/core-rules.md",
|
|
10
10
|
"baselineHash": null,
|
|
11
11
|
"templateHash": null,
|
|
12
|
-
"lastAppliedVersion": "1.10.
|
|
12
|
+
"lastAppliedVersion": "1.10.1",
|
|
13
13
|
"managedBy": "@pm_zhousl/xinyun-ai-init",
|
|
14
14
|
"status": "unknown"
|
|
15
15
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"projectName": "",
|
|
3
|
-
"xinyunAiVersion": "1.10.
|
|
3
|
+
"xinyunAiVersion": "1.10.1",
|
|
4
4
|
"scriptVersion": "2026.07.23",
|
|
5
5
|
"schemaVersion": "1",
|
|
6
6
|
"initializationMode": "fast",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"bindings": "xinyun-ai/sessions/role-session-bindings.json",
|
|
95
95
|
"bindingTemplate": "xinyun-ai-init/templates/role-session-binding.template.json",
|
|
96
96
|
"parentSessionId": null,
|
|
97
|
-
"targetVersion": "1.10.
|
|
97
|
+
"targetVersion": "1.10.1",
|
|
98
98
|
"requiredRoleCount": 5,
|
|
99
99
|
"statusEnum": [
|
|
100
100
|
"pending",
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"sessionId": null,
|
|
7
7
|
"parentSessionId": null,
|
|
8
8
|
"provider": "codex",
|
|
9
|
-
"targetVersion": "1.10.
|
|
9
|
+
"targetVersion": "1.10.1",
|
|
10
10
|
"projectRootHash": null,
|
|
11
11
|
"workspaceScope": {"scopeType": "project-root", "scopePathHashes": [], "scopeRevision": null},
|
|
12
12
|
"repositoryScopeHash": null,
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"roleDisplayName": null,
|
|
56
56
|
"responsibilityLabel": null,
|
|
57
57
|
"titleSource": "role-contract",
|
|
58
|
-
"titleVersion": "1.10.
|
|
58
|
+
"titleVersion": "1.10.1"
|
|
59
59
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pm_zhousl/xinyun-ai-init",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"description": "欣芸技术开发 Agent 流初始化包",
|
|
5
5
|
"bin": {
|
|
6
6
|
"xinyun-ai-init": "bin/xinyun-ai-init.js"
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"verify:init": "node ./scripts/verify-init-package.js",
|
|
17
17
|
"verify:rules": "node ./scripts/verify-rules-package.js",
|
|
18
18
|
"verify:rules:security": "node ./scripts/verify-rules-tarball-security.js",
|
|
19
|
+
"evidence:v1.10": "node ./scripts/collect-v1.10-evidence.js",
|
|
19
20
|
"publish:token": "powershell -ExecutionPolicy Bypass -File ./scripts/publish-with-token.ps1",
|
|
20
21
|
"publish:token:dry": "powershell -ExecutionPolicy Bypass -File ./scripts/publish-with-token.ps1 -DryRun"
|
|
21
22
|
},
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const crypto = require("crypto");
|
|
6
|
+
|
|
7
|
+
const root = path.resolve(__dirname, "..");
|
|
8
|
+
const packageVersion = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8")).version;
|
|
9
|
+
const expectedScenarioIds = Array.from({ length: 14 }, (_, index) => 120 + index);
|
|
10
|
+
const roles = ["project-owner", "project-product", "chief-engineer", "programmer", "test-reviewer"];
|
|
11
|
+
|
|
12
|
+
function parseArgs(argv) {
|
|
13
|
+
const options = { sessionManifest: null, output: null, fixture: path.join(root, "test-scenarios", "fixtures", "v1.10.0-takeover-gate-fixture") };
|
|
14
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
15
|
+
const arg = argv[index];
|
|
16
|
+
if (arg === "--session-manifest") options.sessionManifest = argv[++index];
|
|
17
|
+
else if (arg === "--output") options.output = argv[++index];
|
|
18
|
+
else if (arg === "--fixture") options.fixture = argv[++index];
|
|
19
|
+
else if (arg === "--help" || arg === "-h") {
|
|
20
|
+
console.log("Usage: node scripts/collect-v1.10-evidence.js [--session-manifest path] [--output path] [--fixture path]");
|
|
21
|
+
process.exit(0);
|
|
22
|
+
} else {
|
|
23
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return options;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function sha256File(filePath) {
|
|
30
|
+
return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function readJson(filePath) {
|
|
34
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function writeJson(filePath, value) {
|
|
38
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
39
|
+
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function scanSensitive(value) {
|
|
43
|
+
const text = JSON.stringify(value);
|
|
44
|
+
const markers = [
|
|
45
|
+
/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/i,
|
|
46
|
+
/(?:^|[^a-z])(?:password|passwd|secret|token|authorization|api[_-]?key)\s*[:=]\s*[^\s,}"']+/i,
|
|
47
|
+
/(?:mysql|postgres(?:ql)?|mongodb(?:\+srv)?):\/\/[^\s"']+/i,
|
|
48
|
+
];
|
|
49
|
+
return markers.filter((marker) => marker.test(text)).map((marker) => marker.toString());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function validHostSessionId(value) {
|
|
53
|
+
return typeof value === "string" && value.trim() !== "" && !/^(null|unknown|fake|fixture|placeholder|session-fixture)/i.test(value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function loadSessionManifest(filePath) {
|
|
57
|
+
if (!filePath || !fs.existsSync(filePath)) return null;
|
|
58
|
+
const manifest = readJson(filePath);
|
|
59
|
+
if (manifest.source !== "codex-host-returned") return null;
|
|
60
|
+
if (!Array.isArray(manifest.sessions)) return null;
|
|
61
|
+
const byRole = new Map(manifest.sessions.map((entry) => [entry.roleId, entry]));
|
|
62
|
+
const manifestDirectory = path.dirname(path.resolve(filePath));
|
|
63
|
+
const entries = roles.map((roleId) => byRole.get(roleId) || null);
|
|
64
|
+
if (entries.some((entry) => !entry || !validHostSessionId(entry.sessionId))) return null;
|
|
65
|
+
if (entries.some((entry) => !Array.isArray(entry.scenarios) || entry.scenarios.length !== expectedScenarioIds.length)) return null;
|
|
66
|
+
for (const entry of entries) {
|
|
67
|
+
const scenarioIds = entry.scenarios.map((scenario) => scenario.scenarioId).sort((left, right) => left - right);
|
|
68
|
+
if (JSON.stringify(scenarioIds) !== JSON.stringify(expectedScenarioIds)) return null;
|
|
69
|
+
for (const scenario of entry.scenarios) {
|
|
70
|
+
if (!expectedScenarioIds.includes(scenario.scenarioId) || typeof scenario.input !== "string" || typeof scenario.actualOutput !== "string") return null;
|
|
71
|
+
for (const field of ["interactionLogPath", "beforeSnapshotPath", "afterSnapshotPath"]) {
|
|
72
|
+
const filePathValue = scenario[field];
|
|
73
|
+
if (typeof filePathValue !== "string") return null;
|
|
74
|
+
const resolved = path.resolve(manifestDirectory, filePathValue);
|
|
75
|
+
if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile()) return null;
|
|
76
|
+
}
|
|
77
|
+
const interactionPath = path.resolve(manifestDirectory, scenario.interactionLogPath);
|
|
78
|
+
if (scanSensitive(fs.readFileSync(interactionPath, "utf8")).length > 0) return null;
|
|
79
|
+
const beforeHash = sha256File(path.resolve(manifestDirectory, scenario.beforeSnapshotPath));
|
|
80
|
+
const afterHash = sha256File(path.resolve(manifestDirectory, scenario.afterSnapshotPath));
|
|
81
|
+
if (scenario.beforeSnapshotHash !== beforeHash || scenario.afterSnapshotHash !== afterHash) return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return { entries, manifestDirectory };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function buildScenario(scenarioId, sessionId, source, fixtureBeforeHash, fixtureAfterHash, failureReason) {
|
|
88
|
+
const hasSession = validHostSessionId(sessionId);
|
|
89
|
+
const scenario = {
|
|
90
|
+
scenarioId,
|
|
91
|
+
sessionId: hasSession ? sessionId : null,
|
|
92
|
+
input: hasSession ? source.input || `Host export input for scenario ${scenarioId}` : "not executed: no verified Codex host session export",
|
|
93
|
+
expectedOutput: `v1.10 takeover gate scenario ${scenarioId}`,
|
|
94
|
+
actualOutput: hasSession ? source.actualOutput || "host output supplied without a synthetic result" : "not-verified",
|
|
95
|
+
beforeSnapshotHash: hasSession ? source.beforeSnapshotHash || fixtureBeforeHash : null,
|
|
96
|
+
afterSnapshotHash: hasSession ? source.afterSnapshotHash || fixtureAfterHash : null,
|
|
97
|
+
changedFiles: Array.isArray(source.changedFiles) ? source.changedFiles : [],
|
|
98
|
+
forbiddenOperations: {
|
|
99
|
+
databaseConnection: false,
|
|
100
|
+
sqlExecution: false,
|
|
101
|
+
gitWrite: false,
|
|
102
|
+
businessCodeWrite: false,
|
|
103
|
+
dependencyInstall: false,
|
|
104
|
+
npmPublish: false,
|
|
105
|
+
},
|
|
106
|
+
evidence: hasSession ? [{ type: "real-session-export", sessionId }] : [],
|
|
107
|
+
sensitiveScan: { status: "pass", matches: scanSensitive({ source, sessionId }) },
|
|
108
|
+
result: hasSession ? "pending-review" : "not-verified",
|
|
109
|
+
failureReason: hasSession ? null : failureReason,
|
|
110
|
+
recordedAt: new Date().toISOString(),
|
|
111
|
+
};
|
|
112
|
+
const payload = JSON.stringify(scenario);
|
|
113
|
+
scenario.recordHash = crypto.createHash("sha256").update(payload, "utf8").digest("hex");
|
|
114
|
+
return scenario;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function main() {
|
|
118
|
+
const options = parseArgs(process.argv.slice(2));
|
|
119
|
+
const outputPath = path.resolve(options.output || path.join(root, "test-scenarios", "v1.10.0-behavior-evidence.generated.json"));
|
|
120
|
+
const fixtureBefore = path.join(options.fixture, "before", "project-status.json");
|
|
121
|
+
const fixtureAfter = path.join(options.fixture, "after", "project-status.json");
|
|
122
|
+
if (!fs.existsSync(fixtureBefore) || !fs.existsSync(fixtureAfter)) throw new Error("Fixture must contain before/project-status.json and after/project-status.json");
|
|
123
|
+
|
|
124
|
+
const fixtureBeforeHash = sha256File(fixtureBefore);
|
|
125
|
+
const fixtureAfterHash = sha256File(fixtureAfter);
|
|
126
|
+
const sessions = loadSessionManifest(options.sessionManifest);
|
|
127
|
+
const missingHostExport = !sessions;
|
|
128
|
+
const scenarios = expectedScenarioIds.map((scenarioId) => {
|
|
129
|
+
const role = roles[scenarioId % roles.length];
|
|
130
|
+
const entry = sessions ? sessions.entries.find((candidate) => candidate.roleId === role) : null;
|
|
131
|
+
const source = entry ? entry.scenarios.find((candidate) => candidate.scenarioId === scenarioId) || {} : {};
|
|
132
|
+
return buildScenario(scenarioId, entry && entry.sessionId, source, fixtureBeforeHash, fixtureAfterHash, missingHostExport ? "real-role-session-host-export-missing" : "real-role-session-not-verified");
|
|
133
|
+
});
|
|
134
|
+
const allReal = scenarios.every((scenario) => validHostSessionId(scenario.sessionId) && scenario.evidence.length > 0 && scenario.sensitiveScan.matches.length === 0);
|
|
135
|
+
const report = {
|
|
136
|
+
schemaVersion: 2,
|
|
137
|
+
artifactVersion: packageVersion,
|
|
138
|
+
evidenceType: allReal ? "real-session" : "not-verified",
|
|
139
|
+
executionMode: allReal ? "codex-host-export" : "host-capability-unavailable",
|
|
140
|
+
realAiSessionVerified: allReal,
|
|
141
|
+
publishBlocked: true,
|
|
142
|
+
blockedReason: allReal ? "awaiting-independent-test-review" : "real-role-session-host-unavailable",
|
|
143
|
+
fixturePath: path.relative(root, options.fixture).replace(/\\/g, "/"),
|
|
144
|
+
fixtureHashes: { before: fixtureBeforeHash, after: fixtureAfterHash },
|
|
145
|
+
sessionManifestPath: options.sessionManifest ? path.relative(root, path.resolve(options.sessionManifest)).replace(/\\/g, "/") : null,
|
|
146
|
+
forbiddenOperations: ["database-connection", "sql-execution", "git-write", "business-code-write", "dependency-install", "npm-publish"],
|
|
147
|
+
scenarios,
|
|
148
|
+
};
|
|
149
|
+
writeJson(outputPath, report);
|
|
150
|
+
console.log(JSON.stringify({ output: path.relative(root, outputPath).replace(/\\/g, "/"), realAiSessionVerified: allReal, scenarioCount: scenarios.length, publishBlocked: report.publishBlocked }, null, 2));
|
|
151
|
+
process.exitCode = allReal ? 0 : 3;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
main();
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error(`[v1.10 evidence] ${error.message}`);
|
|
158
|
+
process.exitCode = 2;
|
|
159
|
+
}
|
|
@@ -6,7 +6,7 @@ const crypto = require("crypto");
|
|
|
6
6
|
|
|
7
7
|
const root = path.resolve(__dirname, "..");
|
|
8
8
|
const initRoot = path.join(root, "init", "xinyun-ai-init");
|
|
9
|
-
const CURRENT_VERSION = "1.10.
|
|
9
|
+
const CURRENT_VERSION = "1.10.1";
|
|
10
10
|
|
|
11
11
|
const checks = [];
|
|
12
12
|
|
|
@@ -172,6 +172,11 @@ function verifyPackageFiles() {
|
|
|
172
172
|
packageJson.scripts && packageJson.scripts["verify:init"] === "node ./scripts/verify-init-package.js",
|
|
173
173
|
"缺少发布前校验命令"
|
|
174
174
|
);
|
|
175
|
+
addCheck(
|
|
176
|
+
"package.json scripts 包含 evidence:v1.10",
|
|
177
|
+
packageJson.scripts && packageJson.scripts["evidence:v1.10"] === "node ./scripts/collect-v1.10-evidence.js",
|
|
178
|
+
"缺少 v1.10 真实会话证据采集入口"
|
|
179
|
+
);
|
|
175
180
|
|
|
176
181
|
addCheck(
|
|
177
182
|
"package.json 版本为当前版本",
|
|
@@ -556,7 +561,7 @@ function verifyTestScenarios() {
|
|
|
556
561
|
]);
|
|
557
562
|
|
|
558
563
|
requireIncludes("test-scenarios/README.md", [
|
|
559
|
-
"pm_zhousl-xinyun-ai-init-1.10.
|
|
564
|
+
"pm_zhousl-xinyun-ai-init-1.10.1.tgz",
|
|
560
565
|
"1-133",
|
|
561
566
|
"119",
|
|
562
567
|
"npm run verify:rules",
|
|
@@ -1036,7 +1041,7 @@ function verifyV16Contracts() {
|
|
|
1036
1041
|
}
|
|
1037
1042
|
|
|
1038
1043
|
addCheck("init-result mode 为 initialization", initResult.mode === "initialization");
|
|
1039
|
-
addCheck("init-result targetVersion=
|
|
1044
|
+
addCheck("init-result targetVersion=current", initResult.targetVersion === CURRENT_VERSION);
|
|
1040
1045
|
addCheck("init-result businessCodeChanged 初始为 unknown", initResult.businessCodeChanged && initResult.businessCodeChanged.value === "unknown");
|
|
1041
1046
|
addCheck("task-lock scope=xinyun-ai-control", taskLock.scope === "xinyun-ai-control");
|
|
1042
1047
|
addCheck("task-lock audit 包含 released", Array.isArray(taskLock.audit) && taskLock.audit.some((item) => item.action === "released"));
|
|
@@ -1169,7 +1174,7 @@ function verifyV17Contracts() {
|
|
|
1169
1174
|
]);
|
|
1170
1175
|
|
|
1171
1176
|
requireIncludes("test-scenarios/README.md", [
|
|
1172
|
-
"pm_zhousl-xinyun-ai-init-1.10.
|
|
1177
|
+
"pm_zhousl-xinyun-ai-init-1.10.1.tgz",
|
|
1173
1178
|
"当前 v1.8 既有必测场景为 `scenarios.md` 的 1-105;v1.9 新增 107-118",
|
|
1174
1179
|
"当前观察场景为 `scenarios.md` 的 106 和 119",
|
|
1175
1180
|
"npm run verify:rules",
|
|
@@ -1433,9 +1438,9 @@ function verifyV173Contracts() {
|
|
|
1433
1438
|
"manifest roleSessions.provider 必须为 codex"
|
|
1434
1439
|
);
|
|
1435
1440
|
addCheck(
|
|
1436
|
-
"manifest roleSessions targetVersion=
|
|
1441
|
+
"manifest roleSessions targetVersion=current",
|
|
1437
1442
|
manifestTemplate.roleSessions && manifestTemplate.roleSessions.targetVersion === CURRENT_VERSION,
|
|
1438
|
-
"manifest roleSessions.targetVersion
|
|
1443
|
+
"manifest roleSessions.targetVersion 必须为当前版本"
|
|
1439
1444
|
);
|
|
1440
1445
|
addCheck(
|
|
1441
1446
|
"manifest roleSessions bindings path",
|
|
@@ -1525,7 +1530,7 @@ function verifyV173Contracts() {
|
|
|
1525
1530
|
addCheck("assignments session binding rule mentions real host value", assignments.recordContract && assignments.recordContract.sessionBindingRule.includes("real host-returned value"), "assignments sessionBindingRule 必须说明真实宿主返回值");
|
|
1526
1531
|
|
|
1527
1532
|
addCheck("binding template provider codex", bindingTemplate.provider === "codex", "binding template provider 必须为 codex");
|
|
1528
|
-
addCheck("binding template targetVersion=
|
|
1533
|
+
addCheck("binding template targetVersion=current", bindingTemplate.targetVersion === CURRENT_VERSION, "binding template targetVersion 必须为当前版本");
|
|
1529
1534
|
addCheck("binding template fakeSessionId prohibited", bindingTemplate.degradation && bindingTemplate.degradation.fakeSessionIdProhibited === true, "binding template 必须禁止伪造 sessionId");
|
|
1530
1535
|
addCheck("binding template onboarding readOnly", bindingTemplate.onboarding && bindingTemplate.onboarding.readOnly === true, "binding template onboarding.readOnly 必须为 true");
|
|
1531
1536
|
|
|
@@ -1762,6 +1767,10 @@ function verifyV110Contracts() {
|
|
|
1762
1767
|
"init/xinyun-ai-init/templates/current-task.template.md",
|
|
1763
1768
|
"test-scenarios/v1.10.0-scenarios.md",
|
|
1764
1769
|
"test-scenarios/v1.10.0-behavior-evidence.json",
|
|
1770
|
+
"scripts/collect-v1.10-evidence.js",
|
|
1771
|
+
"test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/README.md",
|
|
1772
|
+
"test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/before/project-status.json",
|
|
1773
|
+
"test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/after/project-status.json",
|
|
1765
1774
|
];
|
|
1766
1775
|
for (const file of requiredFiles) requireFile(file);
|
|
1767
1776
|
|
|
@@ -1858,8 +1867,9 @@ function verifyV110BehaviorEvidence() {
|
|
|
1858
1867
|
}
|
|
1859
1868
|
const scenarios = Array.isArray(report.scenarios) ? report.scenarios : [];
|
|
1860
1869
|
const expectedIds = Array.from({ length: 14 }, (_, index) => 120 + index);
|
|
1861
|
-
const requiredFields = ["scenarioId", "input", "expectedOutput", "actualOutput", "beforeSnapshotHash", "afterSnapshotHash", "changedFiles", "forbiddenOperations", "evidence", "sensitiveScan", "result", "recordedAt"];
|
|
1870
|
+
const requiredFields = ["scenarioId", "sessionId", "input", "expectedOutput", "actualOutput", "beforeSnapshotHash", "afterSnapshotHash", "changedFiles", "forbiddenOperations", "evidence", "sensitiveScan", "result", "recordedAt"];
|
|
1862
1871
|
addCheck("v1.10 behavior evidence source", report.evidenceType === "not-verified" && report.executionMode === "host-capability-unavailable" && report.realAiSessionVerified === false && report.publishBlocked === true, "not-verified evidence is required when role sessions are unavailable");
|
|
1872
|
+
addCheck("v1.10 behavior evidence fixture", report.fixturePath === "test-scenarios/fixtures/v1.10.0-takeover-gate-fixture" && fs.existsSync(path.join(root, report.fixturePath, "before", "project-status.json")) && fs.existsSync(path.join(root, report.fixturePath, "after", "project-status.json")), "persistent fixture boundary exists");
|
|
1863
1873
|
addCheck("v1.10 behavior evidence IDs", JSON.stringify(scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(expectedIds), "scenarios 120-133");
|
|
1864
1874
|
for (const scenario of scenarios) {
|
|
1865
1875
|
const prefix = `v1.10 behavior evidence ${scenario.scenarioId}`;
|
|
@@ -5,7 +5,7 @@ const os = require("os");
|
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const { spawnSync } = require("child_process");
|
|
7
7
|
|
|
8
|
-
const VERSION = "1.10.
|
|
8
|
+
const VERSION = "1.10.1";
|
|
9
9
|
const checks = [];
|
|
10
10
|
|
|
11
11
|
function parseArgs(argv) {
|
|
@@ -191,6 +191,7 @@ function validateVersion(root, target) {
|
|
|
191
191
|
|
|
192
192
|
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.");
|
|
193
193
|
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.");
|
|
194
|
+
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.");
|
|
194
195
|
}
|
|
195
196
|
|
|
196
197
|
function validatePackageFiles(root, target, isTarball) {
|
|
@@ -404,7 +405,7 @@ function validateV17Content(root, target) {
|
|
|
404
405
|
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", "队列"]);
|
|
405
406
|
requireIncludes(root, target, "test-scenarios/scenarios.md", ["当前必测场景为 1-133", "当前观察场景为 106 和 119", "## 55. verify:rules 正常通过", "## 69. verify:rules JSON schema 和重复执行"]);
|
|
406
407
|
requireIncludes(root, target, "test-scenarios/review-template.md", ["55. verify:rules 正常通过", "69. verify:rules JSON schema 和重复执行", "97. Skill 触发测试"]);
|
|
407
|
-
requireIncludes(root, target, "test-scenarios/README.md", ["npm run verify:rules", "pm_zhousl-xinyun-ai-init-1.10.
|
|
408
|
+
requireIncludes(root, target, "test-scenarios/README.md", ["npm run verify:rules", "pm_zhousl-xinyun-ai-init-1.10.1.tgz", "v1.7.2-scenarios.md", "v1.7.3-scenarios.md", "当前版本必测场景为 `scenarios.md` 的 1-133", "106 和 119 为观察项"]);
|
|
408
409
|
}
|
|
409
410
|
|
|
410
411
|
function validateV18Content(root, target) {
|
|
@@ -621,6 +622,10 @@ function validateV110Content(root, target) {
|
|
|
621
622
|
"init/xinyun-ai-init/templates/current-task.template.md",
|
|
622
623
|
"test-scenarios/v1.10.0-scenarios.md",
|
|
623
624
|
"test-scenarios/v1.10.0-behavior-evidence.json",
|
|
625
|
+
"scripts/collect-v1.10-evidence.js",
|
|
626
|
+
"test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/README.md",
|
|
627
|
+
"test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/before/project-status.json",
|
|
628
|
+
"test-scenarios/fixtures/v1.10.0-takeover-gate-fixture/after/project-status.json",
|
|
624
629
|
];
|
|
625
630
|
for (const file of requiredFiles) requireFile(root, target, file);
|
|
626
631
|
|
|
@@ -661,11 +666,12 @@ function validateV110Content(root, target) {
|
|
|
661
666
|
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"]);
|
|
662
667
|
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"]);
|
|
663
668
|
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", "状态源缺失"]);
|
|
669
|
+
requireIncludes(root, target, "scripts/collect-v1.10-evidence.js", ["codex-host-returned", "real-role-session-host-export-missing", "realAiSessionVerified", "recordHash"]);
|
|
664
670
|
|
|
665
671
|
const report = readJson(root, "test-scenarios/v1.10.0-behavior-evidence.json");
|
|
666
672
|
const scenarios = Array.isArray(report.scenarios) ? report.scenarios : [];
|
|
667
673
|
const expectedIds = Array.from({ length: 14 }, (_, index) => 120 + index);
|
|
668
|
-
addCheck(target, "v1.10.behavior-evidence", "behavior", report.evidenceType === "not-verified" && report.executionMode === "host-capability-unavailable" && report.realAiSessionVerified === false && report.publishBlocked === true && 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
|
|
674
|
+
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.");
|
|
669
675
|
}
|
|
670
676
|
|
|
671
677
|
function validateV110CodeGraphContract(root, target, manifest, projectIndex, preflight, onboarding, initResult, currentTask) {
|
package/test-scenarios/README.md
CHANGED
|
@@ -39,7 +39,7 @@ npm pack
|
|
|
39
39
|
随后在临时项目中使用 tarball 测试。注意不要直接执行 `npx <tarball> --force`,该形式可能不会正确调用 bin。推荐:
|
|
40
40
|
|
|
41
41
|
```powershell
|
|
42
|
-
npx --yes --package E:\ai-fabu-xiangmu\AI开发初始化脚本\xinyun-ai-init-npm\pm_zhousl-xinyun-ai-init-1.10.
|
|
42
|
+
npx --yes --package E:\ai-fabu-xiangmu\AI开发初始化脚本\xinyun-ai-init-npm\pm_zhousl-xinyun-ai-init-1.10.1.tgz xinyun-ai-init --force --no-version-check
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### 3. 线上回归测试
|
|
@@ -74,7 +74,7 @@ v1.9.0 的 107-118 行为证据必须保存在 `v1.9.0-behavior-evidence.json`
|
|
|
74
74
|
```powershell
|
|
75
75
|
npm run verify:rules
|
|
76
76
|
npm run verify:rules -- --json
|
|
77
|
-
npm run verify:rules -- --tarball .\pm_zhousl-xinyun-ai-init-1.10.
|
|
77
|
+
npm run verify:rules -- --tarball .\pm_zhousl-xinyun-ai-init-1.10.1.tgz
|
|
78
78
|
npm run verify:rules:security
|
|
79
79
|
```
|
|
80
80
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# v1.10.0 Takeover Gate Fixture
|
|
2
|
+
|
|
3
|
+
This fixture is synthetic and isolated from any business project. It exists so
|
|
4
|
+
the v1.10 behavior material has a real, packageable fixture boundary.
|
|
5
|
+
|
|
6
|
+
It must only be used for rule replay and evidence-shape checks. It does not
|
|
7
|
+
contain a real Codex role session, a database, SQL, Git metadata, credentials,
|
|
8
|
+
or business source files. A replay result is never evidence of real AI
|
|
9
|
+
acceptance.
|
|
10
|
+
|
|
11
|
+
For real-session evidence, provide an external host export to
|
|
12
|
+
`scripts/collect-v1.10-evidence.js`. The export must contain host-returned
|
|
13
|
+
session IDs, interaction logs, and before/after control-plane snapshots. The
|
|
14
|
+
collector rejects missing or synthetic session IDs and otherwise records
|
|
15
|
+
`not-verified`.
|
|
16
|
+
|
|
17
|
+
Expected synthetic control-plane states:
|
|
18
|
+
|
|
19
|
+
- `before/project-status.json`: `blocked` with
|
|
20
|
+
`required-role-session-not-created`.
|
|
21
|
+
- `after/project-status.json`: remains `blocked` when any required role
|
|
22
|
+
session is absent.
|
|
23
|
+
- `before/after` contain no business files and no sensitive values.
|