docs(s5): defer devtools import certification

This commit is contained in:
zizi 2026-06-05 20:09:26 +08:00
parent 1f1bf63074
commit ba40cf4db8
5 changed files with 111 additions and 70 deletions

View File

@ -1,19 +1,27 @@
# DevTool Import Evidence
P0 requires at least one reference-platform import smoke before S5 can claim mini-game import verification.
Current Web/WebGL playable work may continue without developer-tool import evidence. Final S5 import certification and S8 Go/No-Go require both WeChat and Douyin generated projects to be imported by their developer tools before the project can claim mini-game import verification.
Default selection:
Required final import targets:
1. business-primary platform;
2. highest known technical-risk platform;
3. WeChat if neither is known.
1. `wechat_minigame`
2. `douyin_minigame`
`kuaishou_minigame` remains static-gate plus risk-note unless exact official docs, source, or import evidence is available.
Passing evidence is written to `docs/evidence/devtool-import/{target}-{gameVersionId}.json`.
For `simulation-fixture-v1`, final certification requires both:
```text
docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json
docs/evidence/devtool-import/douyin_minigame-simulation-fixture-v1.json
```
Passing evidence must include `target`, `gameVersionId`, `referencePlatformReason`, `result="passed"`, `toolName`, `toolVersion`, `importedProjectPath`, `projectChecksum`, `logPath`, and `createdAt`. `screenshotPath` is optional, but if present it must point to an existing file.
`importedProjectPath` and `logPath` must exist when evidence is recorded. `projectChecksum` must match the stable hash of the imported project directory contents.
`result="blocked"` or `result="failed"` is not passing evidence. Use `DevToolImportBlocker.result="blocked"` when the tool is unavailable, and `DevToolImportBlocker.result="failed"` when import runs but rejects the project. A blocker explains S5 No-Go and keeps the retry path auditable, but it never satisfies `DevToolImportEvidence`.
`result="blocked"` or `result="failed"` is not passing evidence. Use `DevToolImportBlocker.result="blocked"` when the tool is unavailable, and `DevToolImportBlocker.result="failed"` when import runs but rejects the project. A blocker explains S5 import-certification No-Go and keeps the retry path auditable, but it never satisfies `DevToolImportEvidence`.
`ChannelReadinessNote` is only for later channel preparation gaps. It cannot replace `DevToolImportEvidence`, `DevToolImportBlocker`, or channel review.

View File

@ -2,7 +2,7 @@
## 结论
S4 runtime smoke 主线与 S5 mini-game conversion 独立 worktree 已完成一次 `--no-commit` 汇合验证。当前汇合可以进入 fresh spec review + fresh quality review,但 S5 最终验收仍是 No-Go缺少真实开发者工具导入产生`DevToolImportEvidence.result="passed"` 文件。
S4 runtime smoke 主线与 S5 mini-game conversion 独立 worktree 已完成一次 `--no-commit` 汇合验证。当前汇合可以进入 fresh spec review + fresh quality review。2026-06-05 后续决策调整为:当前开发可先推进 Web/WebGL playable开发者工具导入验证后置到 S5 import certification / S8 Go-No-Go但最终仍必须有微信和抖音生成项目`DevToolImportEvidence.result="passed"` 文件。
## 范围
@ -76,7 +76,7 @@ S5 build 结果:
pnpm run smoke:devtool-import -- --target wechat_minigame --game-version-id simulation-fixture-v1 --project dist/packages/simulation-fixture-v1/wechat_minigame --out docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json
```
结果为 EXPECTED No-Goexit 1blocker 为 `DEVTOOL_UNAVAILABLE`。默认路径不会生成 passed evidence也不会把 blocker/note 提升为通过证据。
结果为 EXPECTED No-Goexit 1blocker 为 `DEVTOOL_UNAVAILABLE`。默认路径不会生成 passed evidence也不会把 blocker/note 提升为通过证据。该 No-Go 不再阻塞当前 Web/WebGL playable 开发,但仍阻塞 S5 import certification、S8 Go-No-Go 和 MVP 最终验收。
`/tmp` targeted probes 已通过:
@ -97,7 +97,7 @@ pnpm check:s4-scope
- `dist/packages/simulation-fixture-v1` 已清理。
- `docs/evidence/devtool-import/` 当前只保留 `README.md`
- 未提交 `wechat_minigame-simulation-fixture-v1.json``.log`、`.png` 或 blocker 探针产物。
- 未提交 `wechat_minigame-simulation-fixture-v1.json``douyin_minigame-simulation-fixture-v1.json`、`.log`、`.png` 或 blocker 探针产物。
## 当前门禁
@ -111,7 +111,8 @@ fresh review 结果:
review 后的判断:
- 双 PASS 后可以创建 S5 merge commit。
- 没有真实 DevTools passed evidence 前S5 final acceptance 仍是 No-Go不能解锁 S6/S8 最终验收。
- 当前 Web/WebGL playable 开发可以继续。
- 没有微信和抖音真实 DevTools passed evidence 前S5 import certification 和 S8 Go-No-Go 仍是 No-Go不能宣称小游戏导入验证完成或 MVP 最终 Go。
## 后续

View File

@ -2,9 +2,9 @@
> **For agentic workers:** REQUIRED PROTOCOL: Follow `docs/superpowers/plans/2026-06-01-implementation-review-gate-protocol.md`. Use `superpowers:subagent-driven-development` only. Every implementation Task requires a fresh implementer subagent and two fresh review rounds before the next Task starts.
**Goal:** Generate static WeChat, Douyin, and Kuaishou mini-game project artifacts from the same validated GamePackage and produce conversion reports, static gate evidence, and at least one reference-platform `DevToolImportEvidence.result=passed` record.
**Goal:** Generate static WeChat, Douyin, and Kuaishou mini-game project artifacts from the same validated GamePackage and produce conversion reports and static gate evidence. Current development may continue to the Web/WebGL playable milestone before developer-tool import is executed. Final import certification still requires both WeChat and Douyin generated projects to be imported by their developer tools and recorded as `DevToolImportEvidence.result=passed`.
**Architecture:** S5 treats mini-game support as build-time code conversion and project packaging. All targets consume `GameIR/GameLogicModule/GamePackage/AssetManifest` and implement the S3 `RuntimeSdkContract`; outputs are `MiniGameCodeConversion/MiniGameProject/ConversionReport` plus either a passing `DevToolImportEvidence` or a blocking `DevToolImportBlocker`. No target can own separate business logic. Cocos/Laya/GDevelop/ct-js/Phaser are reference sources for templates, adapters, exporters, and risk checks only; they do not replace the S5 contracts.
**Architecture:** S5 treats mini-game support as build-time code conversion and project packaging. All targets consume `GameIR/GameLogicModule/GamePackage/AssetManifest` and implement the S3 `RuntimeSdkContract`; outputs are `MiniGameCodeConversion/MiniGameProject/ConversionReport` plus final-stage WeChat/Douyin `DevToolImportEvidence` or blocking `DevToolImportBlocker`. No target can own separate business logic. Cocos/Laya/GDevelop/ct-js/Phaser are reference sources for templates, adapters, exporters, and risk checks only; they do not replace the S5 contracts.
**Tech Stack:** TypeScript converter modules, platform adapter codegen, static scanners, checksum utilities, JSON reports, optional manual devtool import evidence.
@ -14,6 +14,12 @@
S5 does not submit to channels, run three-platform device smoke, integrate ads/payments, or claim publishability. It only produces validated debug/import project artifacts.
Current milestone boundary:
- Web/WebGL playable work may continue after Web runtime smoke, mini-game project generation, and static gate checks are passing.
- Developer-tool import is intentionally deferred from the current playable milestone.
- Final S5 import certification and S8 Go/No-Go still require WeChat and Douyin `DevToolImportEvidence.result="passed"`.
## Files
- Create: `packages/shared-contracts/src/minigame-conversion.ts`
@ -310,12 +316,12 @@ Document:
````markdown
# DevTool Import Evidence
P0 requires at least one reference-platform import smoke.
Final import certification requires WeChat and Douyin import smoke. Current Web/WebGL playable work can continue before this certification is complete, but S5 import certification and S8 Go/No-Go remain blocked until both records exist.
Default selection:
1. business-primary platform;
2. highest technical-risk platform;
3. WeChat if neither is known.
1. WeChat is always required for P0 import certification.
2. Douyin is always required for P0 import certification.
3. Kuaishou remains static-gate plus risk-note unless exact official docs, source, or import evidence is available.
Passing evidence must record target, reason, tool version, import result, log path, screenshot path if available, and project checksum. Uncovered platform risks must be written as `ChannelReadinessNote`, not inside `DevToolImportEvidence`.
@ -344,6 +350,13 @@ Example passing evidence:
}
```
Final certification requires both:
```text
docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json
docs/evidence/devtool-import/douyin_minigame-simulation-fixture-v1.json
```
Failed or unavailable import must not be written as `DevToolImportEvidence`. Use `DevToolImportBlocker`:
```json
@ -372,23 +385,28 @@ pnpm --filter api test -- devtool-import-evidence
Expected: evidence without target/reason/result/toolVersion/logPath/projectChecksum fails; `result=blocked` fails for `DevToolImportEvidence` and must be represented as `DevToolImportBlocker`.
- [ ] **Step 3: Select reference platform**
- [ ] **Step 3: Select required import platforms**
Selection logic:
```text
if businessPrimaryTarget is known -> select it
else if highest technical-risk target is known -> select it
else select wechat_minigame
requiredTargets = ["wechat_minigame", "douyin_minigame"]
kuaishou_minigame remains risk-recorded unless exact tool/import evidence exists
```
Write the selected reason into `referencePlatformReason`. For the default fixture, expected selection is:
Write the selected reason into `referencePlatformReason`. For the default fixture, expected records are:
```json
{
"target": "wechat_minigame",
"referencePlatformReason": "wechat_default"
}
[
{
"target": "wechat_minigame",
"referencePlatformReason": "wechat_default"
},
{
"target": "douyin_minigame",
"referencePlatformReason": "highest_technical_risk"
}
]
```
- [ ] **Step 4: Run devtool import smoke**
@ -398,6 +416,7 @@ Command shape:
```bash
pnpm run build:minigame -- --target all --fixture simulation
pnpm run smoke:devtool-import -- --target wechat_minigame --game-version-id simulation-fixture-v1 --project dist/packages/simulation-fixture-v1/wechat_minigame --out docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json
pnpm run smoke:devtool-import -- --target douyin_minigame --game-version-id simulation-fixture-v1 --project dist/packages/simulation-fixture-v1/douyin_minigame --out docs/evidence/devtool-import/douyin_minigame-simulation-fixture-v1.json
```
Expected pass output:
@ -413,6 +432,8 @@ Expected pass output:
If the tool cannot run or import fails, write `DevToolImportBlocker` instead and mark S5 final gate No-Go.
If this step is deferred to continue Web/WebGL playable development, record the deferral as a blocker/risk note and do not claim S5 import certification, S8 Go, channel readiness, or mini-game publishability.
## Task 6: Final S5 Verification
**Files:**
@ -428,9 +449,10 @@ pnpm typecheck
pnpm test
pnpm run build:minigame -- --target all --fixture simulation
pnpm run smoke:devtool-import -- --target wechat_minigame --game-version-id simulation-fixture-v1 --project dist/packages/simulation-fixture-v1/wechat_minigame --out docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json
pnpm run smoke:devtool-import -- --target douyin_minigame --game-version-id simulation-fixture-v1 --project dist/packages/simulation-fixture-v1/douyin_minigame --out docs/evidence/devtool-import/douyin_minigame-simulation-fixture-v1.json
```
Expected: three target projects and reports generated; static gate passes; `docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json` exists with `result="passed"`.
Expected: three target projects and reports generated; static gate passes; both `docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json` and `docs/evidence/devtool-import/douyin_minigame-simulation-fixture-v1.json` exist with `result="passed"`.
- [ ] **Step 2: Check no channel overclaim**
@ -453,43 +475,48 @@ node -e '
const fs = require("fs");
const crypto = require("crypto");
const { execFileSync } = require("child_process");
const path = "docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json";
const evidence = JSON.parse(fs.readFileSync(path, "utf8"));
if (evidence.kind && evidence.kind !== "DevToolImportEvidence") {
throw new Error("DevToolImportBlocker/ChannelReadinessNote cannot satisfy S5 P0");
const evidencePaths = [
"docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json",
"docs/evidence/devtool-import/douyin_minigame-simulation-fixture-v1.json"
];
for (const path of evidencePaths) {
const evidence = JSON.parse(fs.readFileSync(path, "utf8"));
if (evidence.kind && evidence.kind !== "DevToolImportEvidence") {
throw new Error(`${path}: DevToolImportBlocker/ChannelReadinessNote cannot satisfy S5 P0`);
}
for (const field of ["target", "gameVersionId", "referencePlatformReason", "result", "toolName", "toolVersion", "importedProjectPath", "projectChecksum", "logPath"]) {
if (!evidence[field]) throw new Error(`${path}: missing ${field}`);
}
if (evidence.result !== "passed") throw new Error(`${path}: DevToolImportEvidence.result must be passed for S5 P0`);
if (!fs.existsSync(evidence.importedProjectPath)) throw new Error(`${path}: importedProjectPath missing`);
if (!fs.existsSync(evidence.logPath)) throw new Error(`${path}: logPath missing`);
if (evidence.screenshotPath && !fs.existsSync(evidence.screenshotPath)) throw new Error(`${path}: screenshotPath missing`);
const files = execFileSync("find", [evidence.importedProjectPath, "-type", "f"], { encoding: "utf8" })
.trim()
.split("\n")
.filter(Boolean)
.sort();
const hash = crypto.createHash("sha256");
for (const file of files) {
hash.update(file.slice(evidence.importedProjectPath.length + 1));
hash.update(fs.readFileSync(file));
}
const actualChecksum = `sha256:${hash.digest("hex")}`;
if (actualChecksum !== evidence.projectChecksum) {
throw new Error(`${path}: projectChecksum mismatch: expected ${evidence.projectChecksum}, actual ${actualChecksum}`);
}
}
for (const field of ["target", "gameVersionId", "referencePlatformReason", "result", "toolName", "toolVersion", "importedProjectPath", "projectChecksum", "logPath"]) {
if (!evidence[field]) throw new Error(`missing ${field}`);
}
if (evidence.result !== "passed") throw new Error("DevToolImportEvidence.result must be passed for S5 P0");
if (!fs.existsSync(evidence.importedProjectPath)) throw new Error("importedProjectPath missing");
if (!fs.existsSync(evidence.logPath)) throw new Error("logPath missing");
if (evidence.screenshotPath && !fs.existsSync(evidence.screenshotPath)) throw new Error("screenshotPath missing");
const files = execFileSync("find", [evidence.importedProjectPath, "-type", "f"], { encoding: "utf8" })
.trim()
.split("\n")
.filter(Boolean)
.sort();
const hash = crypto.createHash("sha256");
for (const file of files) {
hash.update(file.slice(evidence.importedProjectPath.length + 1));
hash.update(fs.readFileSync(file));
}
const actualChecksum = `sha256:${hash.digest("hex")}`;
if (actualChecksum !== evidence.projectChecksum) {
throw new Error(`projectChecksum mismatch: expected ${evidence.projectChecksum}, actual ${actualChecksum}`);
}
console.log(JSON.stringify({ status: "PASS", evidencePath: path, result: evidence.result, target: evidence.target }));
console.log(JSON.stringify({ status: "PASS", evidencePaths, result: "passed", targets: ["wechat_minigame", "douyin_minigame"] }));
'
```
Expected:
```json
{"status":"PASS","evidencePath":"docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json","result":"passed","target":"wechat_minigame"}
{"status":"PASS","evidencePaths":["docs/evidence/devtool-import/wechat_minigame-simulation-fixture-v1.json","docs/evidence/devtool-import/douyin_minigame-simulation-fixture-v1.json"],"result":"passed","targets":["wechat_minigame","douyin_minigame"]}
```
If only `DevToolImportBlocker` or `ChannelReadinessNote` exists, S5 is No-Go and cannot be accepted.
If either required platform only has `DevToolImportBlocker` or `ChannelReadinessNote`, S5 import certification is No-Go and cannot be accepted. Web/WebGL playable work may still continue under the explicit deferral boundary.
## Review Gate

View File

@ -168,7 +168,8 @@ Web package build
Web smoke PASS
three mini-game projects generated
static gate PASS
one DevToolImportEvidence.result=passed
WeChat DevToolImportEvidence.result=passed
Douyin DevToolImportEvidence.result=passed
submit review
operator approve
feed returns game
@ -176,7 +177,7 @@ event ingestion
dashboard aggregate
```
Missing `DevToolImportEvidence`, `result=blocked`, `result=failed`, or documented blocker-only evidence must make the smoke script FAIL. A documented blocker may be linked in the summary, but it cannot satisfy the smoke PASS condition.
Missing WeChat or Douyin `DevToolImportEvidence`, `result=blocked`, `result=failed`, or documented blocker-only evidence must make the smoke script FAIL. A documented blocker may be linked in the summary, but it cannot satisfy the smoke PASS condition.
- [ ] **Step 2: Run smoke**
@ -268,9 +269,9 @@ Rollback readiness
Go/No-Go rule:
```text
Go requires Manual devtool import evidence with DevToolImportEvidence.result=passed.
Missing evidence, result=blocked, result=failed, or documented blocker-only evidence is a No-Go blocker.
Documented blocker can explain the gap but cannot replace DevToolImportEvidence.result=passed.
Go requires manual developer-tool import evidence for both WeChat and Douyin generated projects, each with `DevToolImportEvidence.result=passed`.
Missing WeChat or Douyin evidence, result=blocked, result=failed, or documented blocker-only evidence is a No-Go blocker.
Documented blocker can explain the gap but cannot replace either required `DevToolImportEvidence.result=passed` record.
```
Deferred P1/P2 must include:

View File

@ -11,7 +11,9 @@ S5 下游于 S0-S4
## Goal / 阶段目标
为同一 `GameVersion/GamePackage` 生成微信、抖音、快手三端小游戏静态代码和项目包,输出 `MiniGameProject``ConversionReport`、static gate 结果和至少一个参考平台 `DevToolImportEvidence.result=passed`。S5 只验证代码转换与项目导入,不做渠道提审、真机 smoke、广告、支付或上架承诺。
为同一 `GameVersion/GamePackage` 生成微信、抖音、快手三端小游戏静态代码和项目包,输出 `MiniGameProject``ConversionReport`、static gate 结果,并在最终导入认证阶段产出微信和抖音两个平台的 `DevToolImportEvidence.result=passed`。S5 只验证代码转换与项目导入,不做渠道提审、真机 smoke、广告、支付或上架承诺。
当前开发推进可以先以 Web/WebGL playable 和三端静态产物生成作为里程碑。微信/抖音开发者工具导入不再阻塞 Web/WebGL playable 开发,但它仍是 S5 import certification、S8 Go/No-Go 和 MVP 最终验收的硬门槛。
## Scope / 范围
@ -22,7 +24,7 @@ P0 做:
- `MiniGameProjectBuilder` 输出三端项目结构;可参考 Cocos 的平台模板和 Laya 的 PAL/小游戏 adapter但不 vendoring 完整引擎。
- `ConversionReport` per target + aggregate。
- static gate入口、配置、adapter/runtime、DOM/BOM、Web-only SDK、外链脚本、资源 hash、包体预算、空项目壳、checksum。
- 至少一个参考平台开发者工具导入 smoke
- 最终导入认证阶段必须完成微信和抖音开发者工具导入 smoke当前 Web/WebGL playable 里程碑可以后置该步骤
- Cocos/Laya 候选后端预研结论,不改变主合同。
不做:
@ -106,23 +108,25 @@ dist/packages/{gameVersionId}/
- 空项目壳必须失败。
- `ConversionReport` 必须包含 status、severity、evidenceLevel、checksum、resourceBudget。
## Reference Platform Rule / 参考平台规则
## Import Certification Rule / 导入认证规则
P0 至少选择一个平台做开发者工具导入 smoke。默认选择
最终 P0 验收必须覆盖微信和抖音两个平台的开发者工具导入 smoke。快手在 P0 中必须保留 static gate、`ConversionReport` 和风险记录;若没有官方文档、真实源码或导入证据证明其平台行为,则不得写成已导入验证。
1. 业务主渠道;如果业务没有指定,则
2. 技术风险最高的平台;如果仍无法判断,则
3. 优先微信,因为生态资料和工具链更成熟,适合作为首个导入 smoke。
微信和抖音的选择原因分别写入 `referencePlatformReason`
`DevToolImportEvidence.result` 必须是 `passed` 才能满足 P0。若执行时无法安装或使用开发者工具或导入失败必须产出 `DevToolImportBlocker`;如只是渠道材料/后续准备风险,则产出 `ChannelReadinessNote`。这两者都不能替代 `DevToolImportEvidence`,且在 S5/S8 gate 中必须作为 blocker/No-Go 处理。
- 微信默认使用 `wechat_default`,除非业务明确指定微信是主渠道。
- 抖音如果是业务主渠道,使用 `business_primary`;否则作为第二参考平台使用 `highest_technical_risk` 或后续新增的明确原因值。
`DevToolImportEvidence.result` 必须是 `passed` 才能满足最终 P0 导入认证。若执行时无法安装或使用开发者工具,或导入失败,必须产出 `DevToolImportBlocker`;如只是渠道材料/后续准备风险,则产出 `ChannelReadinessNote`。这两者都不能替代 `DevToolImportEvidence`,且在 S5 import certification 和 S8 Go/No-Go gate 中必须作为 blocker/No-Go 处理。
## Acceptance Criteria / 验收标准
- 同一 `GamePackage` 生成三端 `MiniGameProject`
- 三端 static gate 全部 PASS。
- 每个平台都有 `ConversionReport`,失败时有 reasonCode 和修复位置。
- 至少一个参考平台有 `DevToolImportEvidence.result=passed`
- 如果只有 `DevToolImportBlocker``ChannelReadinessNote`P0 不通过。
- 当前 Web/WebGL playable 里程碑Web runtime smoke 通过Web/WebGL preview 可交互,三端静态项目和 static gate 通过;可以后置微信/抖音开发者工具导入。
- 最终导入认证:微信和抖音都必须有 `DevToolImportEvidence.result=passed`
- 如果微信或抖音只有 `DevToolImportBlocker``ChannelReadinessNote`,最终 P0 / S8 Go 不通过。
- 未覆盖平台不能在文案或验收中写成真机可玩或可上架。
## Failure Paths / 失败路径
@ -132,7 +136,7 @@ P0 至少选择一个平台做开发者工具导入 smoke。默认选择
| DOM/BOM 被发现 | conversion fail | 回 S3 修 logic 或 adapter |
| 缺平台入口/配置 | static gate fail | 修 project builder |
| 资源超限 | report severity=important | 压缩或拆包P0 不静默通过 |
| 导入 smoke 失败或无法执行 | 写 `DevToolImportBlocker`S5/S8 No-Go | 保留 debug 包和日志,修复后重新导入 |
| 微信或抖音导入 smoke 失败或无法执行 | 写 `DevToolImportBlocker`当前 Web/WebGL playable 可继续推进,但 S5 import certification / S8 Go-No-Go 为 No-Go | 保留 debug 包和日志,修复后重新导入 |
| Cocos/Laya 预研失败 | 记录原因 | 不影响自研主线 |
## Verification Commands / 验证命令