test(refactor): [BASE-01] freeze published core and chapter baselines

This commit is contained in:
Harvey Zhao committed 2026-09-10 18:36:02 +08:00
1 parent 7a5354e356
commit 1d705b3056
10 files changed
+454 -7

No files matched your search

+2 -1
View File
@@ -4,4 +4,5 @@
node_modules
package-lock.json
lerna-debug.log
yarn.lock
yarn.lock
refactor/.cache/
+2 -1
View File
@@ -8,7 +8,7 @@
- 工作分支:`codex/compatible-modernization`。
- 起点:`master`,`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。
- 清点范围:22 个 workspace 包,包括核心、16 个插件、2 个 proxy、2 个工具、1 个文档站;另含 React/Vue 示例、浏览器 demo、构建和发布脚本。
- 当前完成的是计划与文档基础设施,生产代码重构尚未开始。提交以任务 ID 对应的 Git 历史为准;本地提交不代表已推送或发布。
- 已进入实施,真实发布基线及当前执行结果见 progress.md;生产迁移与测试基础设施进度分别记录。提交以任务 ID 对应的 Git 历史为准;本地提交不代表已推送或发布。
- 本目录位于仓库根目录,避免被 `docs/` 的站点部署流程直接作为产品文档发布。
## 从哪里开始
@@ -34,6 +34,7 @@
| [变更记录模板](changes/TEMPLATE.md) | 每次行为/类型/结构变化的详细记录 |
| [任务数据](tasks.json) | 任务状态和依赖的唯一数据来源 |
| [包基线](package-inventory.json) | 包版本、入口、声明、源码清单及对应 demo 的初始快照 |
| [发布基线与重跑说明](baselines/README.md) | 固定 npm tarball、完整性及已知源码/发布差异 |
## 维护规则
+30
View File
@@ -0,0 +1,30 @@
# 已发布基线
BASE-01 于 2026-09-10 固定核心与 chapter 的 npm 发布内容,数据在 [releases.json](releases.json)。这不是全生态兼容通过报告。
| 包 | 工作区版本 | 已固定发布基线 | 后续目标 |
| --- | --- | --- | --- |
| artplayer | 5.4.1 | 5.4.0 | 6.0.0 |
| artplayer-plugin-chapter | 1.1.0 | 1.1.0 | 2.0.0 |
查询 registry.npmjs.org 时 artplayer/5.4.1 返回 404,latest 为 5.4.0。工作区源码基线仍是 40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f;不能把两者混同,也不将 npm 观测永久视为最新状态。发布前重新检查目标版本占用。
两个发布版本的 registry gitHead 均为 daf133b22630b4a0eecfa3336bbddab0e9119d96,但该提交的核心/chapter manifest 是 5.3.1/1.0.3。Git tag 5.4.0 对应 65e51751cd0c0db0bd00b5d7deb925d52cfaf3ef,其 manifest 版本为 5.4.0/1.1.0。来源声明与版本匹配的 tag 分别登记,未证明任一源码可逐字重建发布 tarball;消费者行为的权威参照是冻结的 tarball。
## 已知支持边界
- 先以核心 5.4.0、chapter 1.1.0 建立首组发布对照,不等同把历史支持范围缩小到这两个版本。
- 两个发布 manifest 的 browserslist 都是 last 1 Chrome version;没有固定浏览器版本或 engines/peerDependencies 的最低核心声明。不能据此虚构 Chrome 最低版本或断言 chapter 支持任意核心。
- 当前构建脚本目标为现代 es2020、legacy es2015;它是源码构建目标,不是已验证的设备/codec 能力清单。BASE-08 将支持矩阵落实到版本和样本。
- 当前文档说明 5.1.0 起核心只内置简体中文/英文,其他语言通过资源导入;BASE-05 必须保留相关子路径消费。
- BASE-02/03/04/05 继续捕获运行时、事件、DOM、类型和旧消费契约。其余 20 包的发布基线在 JSON 中明确标为待核实,各包契约任务负责补齐。此阶段没有真实播放或旧核心/插件兼容结论。
## 重跑
运行 `node refactor/scripts/releases.mjs`。需要 Node 20+、PATH 中的 tar(本机 Windows bsdtar 3.8.8);首次从固定 npm URL 下载,缓存于忽略目录 refactor/.cache/releases。已缓存时离线验证 SHA-512 SRI、SHA-256、逐文件哈希、manifest 名称/版本和声明的 main/module/types/legacy 文件存在性。核心 41 文件,chapter 6 文件。
运行 `node --test refactor/scripts/releases.test.mjs` 验证损坏内容和不一致哈希会失败。缺 tar、网络失败或内容不一致明确退出非零,不自动更新基线或降级忽略。
脚本不安装或执行发布包,不修改生成产物,不把整个 tarball 解压到工作区。归档成员通过 tar 读到内存;后续浏览器服务可复用 ensureArchive/readMember。仅缓存写入,JSON 与说明为持久来源记录;没有新增生产依赖。
修改冻结基线必须通过独立任务和变更记录;不能直接覆盖哈希来消除回归。真实样本或报告一旦生成,绑定包版本/完整性和测试 ID。
+301
View File
@@ -0,0 +1,301 @@
{
"schemaVersion": 1,
"capturedAt": "2026-09-10T10:34:31.411Z",
"workspaceBaselineCommit": "40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f",
"captureStartCommit": "7a5354e356b7d6af5b3daf9280699e2e90e05a7d",
"registry": "https://registry.npmjs.org",
"observations": [
{
"name": "artplayer",
"workspaceVersion": "5.4.1",
"requestedMetadataStatus": 404,
"observedLatestStable": "5.4.0",
"impact": "Use published 5.4.0 for consumers, preserve workspace 5.4.1 as separate source baseline; target remains 6.0.0."
},
{
"issue": "Registry gitHead is stale for both releases",
"impact": "Keep registry claims and matching-version tag separately; do not assert tarball is reproduced by either source commit."
}
],
"releases": [
{
"name": "artplayer",
"version": "5.4.0",
"metadataUrl": "https://registry.npmjs.org/artplayer/5.4.0",
"tarball": "https://registry.npmjs.org/artplayer/-/artplayer-5.4.0.tgz",
"integrity": "sha512-2B+plbx8N2yNsjK4nJU3+EOG8TULm1LRZk/QPkWRAMEX2Ee/MSnZG/WJYz8kcoZxZuLKcQ3uXifqLuPxZOH29A==",
"sha256": "42b269a66b9658d53f9a92572bb36d656ea9af56254a387b3a69c7ddea43979e",
"archiveBytes": 133746,
"manifest": {
"name": "artplayer",
"version": "5.4.0",
"description": "ArtPlayer.js is a modern and full featured HTML5 video player",
"author": "Harvey Zhao <laozhaochaguan@gmail.com>",
"license": "MIT",
"homepage": "https://artplayer.org",
"repository": {
"type": "git",
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
},
"bugs": {
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
},
"keywords": [
"html5",
"video",
"player"
],
"exports": {
".": {
"types": "./types/artplayer.d.ts",
"import": "./dist/artplayer.mjs",
"require": "./dist/artplayer.js"
},
"./legacy": {
"types": "./types/artplayer.d.ts",
"import": "./dist/artplayer.legacy.js",
"require": "./dist/artplayer.legacy.js"
},
"./i18n/*": {
"types": "./types/i18n.d.ts",
"import": "./dist/i18n/*.mjs",
"require": "./dist/i18n/*.js"
}
},
"main": "./dist/artplayer.js",
"module": "./dist/artplayer.mjs",
"types": "./types/artplayer.d.ts",
"typesVersions": {
"*": {
"i18n/*": [
"types/i18n.d.ts"
],
"legacy": [
"types/artplayer.d.ts"
]
}
},
"legacy": "./dist/artplayer.legacy.js",
"browserslist": "last 1 Chrome version",
"dependencies": {
"option-validator": "^2.0.6"
}
},
"files": {
"package/README.md": "b2e7985fe1cb42822e6a862acedf96bfebdd5a4800ae8e7817fd79e992881748",
"package/dist/artplayer.js": "f1db1fa3406aa6d41baa7c554749429a8e79f99d56a794bde23345eb9c07573f",
"package/dist/artplayer.legacy.js": "cef83f9dac8a343060329ea6c5d603f0e7811fd0fd6c1590ae1c47f9e0afc9bb",
"package/dist/artplayer.mjs": "a1800b37ac7549f52fa960fe28bc6e1c69ec18bd4bc9a7e2534aecc3df10eb3e",
"package/dist/i18n/ar.js": "61c43469ee95a00dc624583f418653e3dcbf48b24ae6a4c203ad986234852365",
"package/dist/i18n/ar.mjs": "68922fdc9f80d3321ea0654c8ff8f5875b6715103d2b14ffcf17f93738b39cf9",
"package/dist/i18n/cs.js": "ad7bbf8853204a6955ef84bfbd932cab3f141a7e73a8145f28ba7a5b2b83b7c0",
"package/dist/i18n/cs.mjs": "29a489be767fda9d46b59c9adbaad323f17a5e67daf7f7aa78b7ce8fb5b4d63c",
"package/dist/i18n/es.js": "aaa95cc9645b734c58fba06fdbcdda962c4cb3a0e7eb6206f06d6168208cd86b",
"package/dist/i18n/es.mjs": "331d2ef74da2eec8f3304fec0b5340c795d9c1eec24e08167c9a7b66bf30973b",
"package/dist/i18n/fa.js": "c998467261cbdfd2c3fb16c0ae4b2c48c409f42f41aea35ed94766f1e12819d5",
"package/dist/i18n/fa.mjs": "b4c98894b46975cebf5ea9088bcf0b5bdfd408bc3c82f4e2e9128133c7de2d4d",
"package/dist/i18n/fr.js": "6b06e16b1fb01c8695fb5c10b32a00421399180de5dc5d845ce17010f2fd3e66",
"package/dist/i18n/fr.mjs": "abe8e3548fa7304f302e2c74818a6176edee8c3b65e33cb6f62e96d130749ee5",
"package/dist/i18n/id.js": "a5832c4bfc03c7f16418bf4b324d9773895541dc823ece9114741794737aad74",
"package/dist/i18n/id.mjs": "a40a433be6ca1ac1ee1810fe805ee60784d349e59b9ad82ea80201d660db4e68",
"package/dist/i18n/pl.js": "2491487062bdfc91d60f17c6e9a83ee196c991216d15f525fe3536b98873da2c",
"package/dist/i18n/pl.mjs": "ad8ea2c03785edbfe1f35761bec21b8a04213f9fa88a794d850bb3973564930f",
"package/dist/i18n/ru.js": "2d3a9ee6533cb6fa961f0a24a25ce63cc76992fca17e1769b6fa75104f8a1529",
"package/dist/i18n/ru.mjs": "a89b8c36cfd7c181c2b31aa823deda3d7c37b56b2b81746338c52ea1c1d93352",
"package/dist/i18n/tr.js": "438b06a4c3f479a2901b0085eaa7bdba8eaef87bdb07ff3faa559c85403fe433",
"package/dist/i18n/tr.mjs": "cc96f9cbb9c1587d5cd8f25b0b9800678ad76e93de089ae42c38dee16e6fe8fa",
"package/dist/i18n/vi.js": "1ffbd62843a902ea2967eab46432d3fc548f5633e53eed104314b523cacc46a8",
"package/dist/i18n/vi.mjs": "7872ded84622bcda20e8c1d70c597c2ba071b50701900efa47cc4683ee17f1a2",
"package/dist/i18n/zh-tw.js": "2d43577f98456488196921e1ec721695a95e1b8c827077286b02ce3fb987e8ff",
"package/dist/i18n/zh-tw.mjs": "7ec638b4babe59d3ab1d3e64abdd74a96fefb260a50e2cd7240f8d50a1340925",
"package/package.json": "d3dd8bb2f4c0629b60a88ca8328f5813f33ab56502989b63de31446cc9516d99",
"package/types/artplayer.d.ts": "f2bc49e8b708ec27d9f5c138cf32099318abbb5e6135a7ee723b20511dab7026",
"package/types/component.d.ts": "08a960348dc459a9ff529ab8e5bdae5fc2fd76448028d7743f58480ea8414cbd",
"package/types/config.d.ts": "97322dce493ac3d1160f426e4fd0ba89fa746f7d66bfbeabd9f45454198560ad",
"package/types/cssVar.d.ts": "2ff9827aa10bf326f60f6cda7556a94fdcabafba529185a1ceae46d865f33697",
"package/types/events.d.ts": "3d9ee111908d93efb4c531cdb6c82d698526328d78ecf77e2488d4aa1d43a310",
"package/types/i18n.d.ts": "01e7d7e7f775166eed6dbc6b86feb26306302fcbfe33fa01b7e363a14b3ef2b0",
"package/types/icons.d.ts": "61ce1b0cb9bc7488263b644419b5fd5a13e72de1493c8113eee81d5174f1234b",
"package/types/option.d.ts": "b4735183a4c9dde7620e178950df9f9d1c18bbaa79ef8f9f85ec6c51a5e47662",
"package/types/player.d.ts": "bce1aa214bfb10b017574f6175a400c059b4d56041c4b2329cc0873c66ac94e4",
"package/types/quality.d.ts": "dcca8c0f5b5c25373f85825a274fc3ee8beeffd7c8b2a978468e039ff4946a9e",
"package/types/setting.d.ts": "a60ed81da780439a55ee22ebe2611d936bd45da0d98e6bf44c92e9a5d9047492",
"package/types/subtitle.d.ts": "92f711ad0f7924e609ad4425cd26d19c73eb027cccddc6d89fcf9b8e334db065",
"package/types/template.d.ts": "b5f9bff43b4816bd2e3531a3a1750b8014fcf63d421fbc786341cedb1429035c",
"package/types/utils.d.ts": "4405a0d40628eaf40357fe31286f26f21b09b14d74581fff32358bb78fd789f4"
},
"sourceMapping": {
"registryGitHead": "daf133b22630b4a0eecfa3336bbddab0e9119d96",
"versionAtRegistryGitHead": "5.3.1",
"versionTag": "5.4.0",
"versionTagCommit": "65e51751cd0c0db0bd00b5d7deb925d52cfaf3ef",
"versionAtTag": "5.4.0",
"exactSourceReproduction": "not-yet-verified"
}
},
{
"name": "artplayer-plugin-chapter",
"version": "1.1.0",
"metadataUrl": "https://registry.npmjs.org/artplayer-plugin-chapter/1.1.0",
"tarball": "https://registry.npmjs.org/artplayer-plugin-chapter/-/artplayer-plugin-chapter-1.1.0.tgz",
"integrity": "sha512-ji66Lr2K2S+OjFMuMby3yq+pefWlOC51Sbpop/DIr2N6w3F0smrF+YZbshN1Dy8/Tx1TYpT7N6WkkZWy5Jix1w==",
"sha256": "4c3173661854ff96f643a479c0f1c2db7ce9e54681523bd059a7dd9bd77eeada",
"archiveBytes": 4221,
"manifest": {
"name": "artplayer-plugin-chapter",
"version": "1.1.0",
"description": "chapter plugin for ArtPlayer",
"author": "Harvey Zhao <laozhaochaguan@gmail.com>",
"license": "MIT",
"homepage": "https://artplayer.org",
"repository": {
"type": "git",
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
},
"bugs": {
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
},
"keywords": [
"html5",
"video",
"player"
],
"exports": {
".": {
"types": "./types/artplayer-plugin-chapter.d.ts",
"import": "./dist/artplayer-plugin-chapter.mjs",
"require": "./dist/artplayer-plugin-chapter.js"
},
"./legacy": {
"types": "./types/artplayer-plugin-chapter.d.ts",
"import": "./dist/artplayer-plugin-chapter.legacy.js",
"require": "./dist/artplayer-plugin-chapter.legacy.js"
}
},
"main": "./dist/artplayer-plugin-chapter.js",
"module": "./dist/artplayer-plugin-chapter.mjs",
"types": "./types/artplayer-plugin-chapter.d.ts",
"legacy": "./dist/artplayer-plugin-chapter.legacy.js",
"browserslist": "last 1 Chrome version"
},
"files": {
"package/README.md": "04f1d3338acdf7c4f56ac3596d7c5c3282f508400208cb6142da064ced7e72dc",
"package/dist/artplayer-plugin-chapter.js": "c2aaee11bf1db765433b01d9f8dd3978e41fa4d39655db00ebd03fc0be3e35e0",
"package/dist/artplayer-plugin-chapter.legacy.js": "c2aaee11bf1db765433b01d9f8dd3978e41fa4d39655db00ebd03fc0be3e35e0",
"package/dist/artplayer-plugin-chapter.mjs": "61342a069b84e0731d44a2464d0dfe637d1514d0037c740371fc866c516d2209",
"package/package.json": "233ed9b732e14cb06955536157ba1650c4cffded74015a2417942e70ee5aca04",
"package/types/artplayer-plugin-chapter.d.ts": "4ce65f8a55ed8f53ddd7f1cd7324923aacefeaee209d58d5981e1434050a6962"
},
"sourceMapping": {
"registryGitHead": "daf133b22630b4a0eecfa3336bbddab0e9119d96",
"versionAtRegistryGitHead": "1.0.3",
"versionTag": "5.4.0",
"versionTagCommit": "65e51751cd0c0db0bd00b5d7deb925d52cfaf3ef",
"versionAtTag": "1.1.0",
"exactSourceReproduction": "not-yet-verified"
}
}
],
"remainingPackages": [
{
"name": "artplayer-plugin-ads",
"workspaceVersion": "2.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-ambilight",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-asr",
"workspaceVersion": "2.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-audio-track",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-auto-thumbnail",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-chromecast",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-danmuku",
"workspaceVersion": "5.3.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-danmuku-mask",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-dash-control",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-document-pip",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-hls-control",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-jassub",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-multiple-subtitles",
"workspaceVersion": "1.2.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-vast",
"workspaceVersion": "1.2.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-plugin-vtt-thumbnail",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-proxy-canvas",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-proxy-mediabunny",
"workspaceVersion": "1.2.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-tool-iframe",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-tool-thumbnail",
"workspaceVersion": "4.4.0",
"releaseBaseline": "not-yet-verified"
},
{
"name": "artplayer-vitepress",
"workspaceVersion": "1.1.0",
"releaseBaseline": "not-yet-verified"
}
]
}
@@ -0,0 +1,23 @@
# BASE-01 核心与 chapter 发布基线
- 日期:2026-09-10;分支:codex/compatible-modernization;起点:7a5354e3。
- 提交主题:`test(refactor): [BASE-01] freeze published core and chapter baselines`。
- 关联:API-09、ADR-019;本任务是来源与可重跑验证基础,不修改生产 API。
## 实际交付
固定 artplayer@5.4.0 和 artplayer-plugin-chapter@1.1.0 的 metadata URL、SRI、archive SHA-256、manifest、47 个成员哈希以及来源差异。新增无第三方 Node 依赖的验证脚本和损坏负例,缓存忽略规则及基线维护说明。
artplayer@5.4.1 当前未发布(registry 返回 404);两个包的 registry gitHead 版本也与发布包不符,不能将它当成确定的发布源码。版本匹配的本地 tag 单独记录,精确构建重现仍待验证。其余 20 包及最低 TS/浏览器/核心支持范围尚未验证。
## 验证
- `node refactor/scripts/releases.mjs`:两个包 SHA-512/SHA-256、核心 41/chapter 6 成员哈希及主要 manifest 入口存在性通过。
- `node --test refactor/scripts/releases.test.mjs`:1 项通过,含替换 bytes 和错误 SHA-256 的负例。
- `node --check refactor/scripts/releases.mjs` 和计划检查通过。
- 环境:Node 25.2.1,Windows bsdtar 3.8.8;来源和完整哈希见 baselines/releases.json。
- 未运行生产播放/浏览器/类型回归;入口存在性不等于入口可运行,后续 BASE 任务继续验证。
## 兼容、交接与回退
没有修改 core/plugin 源码、manifest、锁文件或分发内容;目标仍为核心 6.0.0/chapter 2.0.0。验证脚本职责和命令见 baselines/README.md。可独立回退本提交;缓存是可重下载的本地文件。BASE-01 达到最小来源验收,后续先推进 BASE-02 和工程固定依赖。
+3 -2
View File
@@ -4,7 +4,7 @@
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 211 项,范围 22 个包及工作区/示例。
状态:todo 199 / doing 0 / blocked 0 / done 12 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
状态:todo 198 / doing 0 / blocked 0 / done 13 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
@@ -58,7 +58,7 @@
| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 |
| --- | --- | --- | --- | --- | --- | --- |
| BASE-01 | workspace<br>固定核心与试点的最小发布基线 | DOC-07 | 核心及 chapter 的 npm tarball/integrity、源码 SHA、已知支持窗口;其他包标待核对 | 核心/试点来源可重跑;不虚构全生态已验证,各包 01 步负责补齐自身历史发布基线 | H | todo |
| BASE-01 | workspace<br>固定核心与试点的最小发布基线 | DOC-07 | 核心及 chapter 的 npm tarball/integrity、源码 SHA、已知支持窗口;其他包标待核对 | 核心/试点来源可重跑;不虚构全生态已验证,各包 01 步负责补齐自身历史发布基线 | H | done |
| BASE-02 | workspace<br>捕获公共 API 和属性描述符 | BASE-01 | 核心与试点的构造/默认值/静态和实例 API 快照,其余包由 01/02 步补齐;登记契约/版本/固定测试 ID/命令/报告与负责任务 | 真实发布包反射与旧用户调用可重跑,未验证项明确 | H | todo |
| BASE-03 | workspace<br>捕获事件、异步和生命周期 | BASE-02 | ready/restart/destroy、Promise、切源/插件事件 trace;登记契约/版本/固定测试 ID/命令/报告与负责任务 | 成功、失败、重入和多实例有断言,历史缺陷有标记;使用已发布包和最小可重跑探针启动,不等待后续 ENG 服务 | H | todo |
| BASE-04 | workspace<br>捕获 DOM、CSS 和官方 demo | BASE-02 | 核心模板/类名/变量、键盘/焦点/可访问名称基线及全 demo 路径映射;docs-browser-testing.md 中 HTML/编辑器的脚本来源与存储状态;登记契约/版本/固定测试 ID/命令/报告与负责任务 | 核心/试点用户样式和输入用法已记录,其他 demo 运行状态与未知项明确;使用已发布包和最小可重跑探针启动,不等待后续 ENG 服务 | M | todo |
@@ -412,3 +412,4 @@
- DOC-10: [记录](changes/2026-09-10-DOC-10-github-ci-cd.md)
- DOC-11: [记录](changes/2026-09-10-DOC-11-major-version-policy.md)
- DOC-12: [记录](changes/2026-09-10-DOC-12-execution-readiness-review.md)
- BASE-01: [记录](changes/2026-09-10-BASE-01-published-baseline.md) [记录](baselines/releases.json)
+7 -1
View File
@@ -1,6 +1,12 @@
# 进度与证据
## 当前阶段:DOC-12 开发前计划复审
## 当前实施:BASE-01 已发布基线
2026-09-10,goal 开始执行。固定核心 5.4.0/chapter 1.1.0 的真实 tarball、47 个成员哈希和支持范围未知项。核心工作区 5.4.1 未发布,两包 registry gitHead 版本过旧,均已如实记录。详见 [BASE-01 交付](changes/2026-09-10-BASE-01-published-baseline.md)。
两个包完整性和入口存在性验证通过,损坏检测 1 项测试通过。完成 12 项规划及 1 项实施基础任务;198 项待办。没有生产 TS 迁移或浏览器通过结论,没有推送/发布。下一步 BASE-02 捕获公开 API,ENG-01 固定依赖与运行环境。
## 2026-09-10:DOC-12 开发前计划复审
2026-09-10,再次检查依赖和验收,修正首轮复盘间接等待 mask 设备、版本准备缺实施任务,补清基线启动、站点分发分类、SSR 边界与契约覆盖索引。详见 [DOC-12 记录](changes/2026-09-10-DOC-12-execution-readiness-review.md) 和 [执行门槛](execution-gates.md)。
+70
View File
@@ -0,0 +1,70 @@
import assert from 'node:assert/strict'
import { createHash } from 'node:crypto'
import { execFileSync } from 'node:child_process'
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
export const refactorDir = fileURLToPath(new URL('../', import.meta.url))
export const cacheDir = path.join(refactorDir, '.cache/releases')
export const hash = (bytes, algorithm = 'sha256', encoding = 'hex') => createHash(algorithm).update(bytes).digest(encoding)
export function verifyIntegrity(bytes, release) {
assert.equal(`sha512-${hash(bytes, 'sha512', 'base64')}`, release.integrity, `Integrity mismatch: ${release.name}`)
assert.equal(hash(bytes), release.sha256, `Archive hash mismatch: ${release.name}`)
}
export function archiveFiles(archive) {
const names = execFileSync('tar', ['-tzf', archive], { encoding: 'utf8' }).trim().split(/\r?\n/)
assert.equal(new Set(names).size, names.length, 'Duplicate archive entries')
for (const name of names) {
assert(name.startsWith('package/') && !name.includes('\\') && !name.split('/').includes('..'), `Invalid archive path: ${name}`)
}
return names.filter(name => !name.endsWith('/')).sort()
}
// Read a member to memory; never extract untrusted paths into the working tree.
export function readMember(archive, member) {
assert(member.startsWith('package/') && !member.includes('..') && !member.includes('\\'), 'Invalid member')
return execFileSync('tar', ['-xOzf', archive, member], { maxBuffer: 16 * 1024 * 1024 })
}
export async function ensureArchive(release) {
assert(/^[a-z0-9-]+$/.test(release.name) && /^\d+\.\d+\.\d+$/.test(release.version), 'Invalid release identifier')
const archive = path.join(cacheDir, `${release.name}-${release.version}.tgz`)
if (!fs.existsSync(archive)) {
const url = new URL(release.tarball)
assert.equal(url.origin, 'https://registry.npmjs.org', 'Unexpected registry')
const response = await fetch(url, { redirect: 'error', signal: AbortSignal.timeout(30000) })
assert(response.ok, `Download failed: ${response.status} ${release.name}`)
const bytes = Buffer.from(await response.arrayBuffer())
verifyIntegrity(bytes, release)
fs.mkdirSync(cacheDir, { recursive: true })
fs.writeFileSync(archive, bytes)
}
verifyIntegrity(fs.readFileSync(archive), release)
return archive
}
export async function verifyReleases() {
const baseline = JSON.parse(fs.readFileSync(path.join(refactorDir, 'baselines/releases.json'), 'utf8'))
for (const release of baseline.releases) {
const archive = await ensureArchive(release)
const names = archiveFiles(archive)
assert.deepEqual(names, Object.keys(release.files).sort(), `File inventory changed: ${release.name}`)
for (const name of names) {
assert.equal(hash(readMember(archive, name)), release.files[name], `File changed: ${name}`)
}
const manifest = JSON.parse(readMember(archive, 'package/package.json'))
assert.equal(manifest.name, release.name)
assert.equal(manifest.version, release.version)
for (const field of ['main', 'module', 'types', 'legacy']) {
if (manifest[field]) assert(names.includes(`package/${manifest[field].replace(/^\.\//, '')}`), `Missing ${field}: ${release.name}`)
}
console.log(`Verified ${release.name}@${release.version}: SHA-512, SHA-256, ${names.length} files and manifest entrypoints`)
}
}
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
await verifyReleases()
}
+11
View File
@@ -0,0 +1,11 @@
import assert from 'node:assert/strict'
import { test } from 'node:test'
import { hash, verifyIntegrity } from './releases.mjs'
test('release integrity rejects corrupted bytes and inconsistent frozen digests', () => {
const bytes = Buffer.from('known release artifact')
const release = { name: 'fixture', integrity: `sha512-${hash(bytes, 'sha512', 'base64')}`, sha256: hash(bytes) }
assert.doesNotThrow(() => verifyIntegrity(bytes, release))
assert.throws(() => verifyIntegrity(Buffer.from('replaced artifact'), release), /Integrity mismatch/)
assert.throws(() => verifyIntegrity(bytes, { ...release, sha256: '0'.repeat(64) }), /Archive hash mismatch/)
})
+5 -2
View File
@@ -229,11 +229,14 @@
"dependsOn": [
"DOC-07"
],
"status": "todo",
"status": "done",
"risk": "H",
"deliverable": "核心及 chapter 的 npm tarball/integrity、源码 SHA、已知支持窗口;其他包标待核对",
"acceptance": "核心/试点来源可重跑;不虚构全生态已验证,各包 01 步负责补齐自身历史发布基线",
"evidence": []
"evidence": [
"changes/2026-09-10-BASE-01-published-baseline.md",
"baselines/releases.json"
]
},
{
"id": "BASE-02",