mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 10:56:15 -08:00
fix(release): [REL-02] accept Yarn directory entries in candidate archives
This commit is contained in:
1 parent
e54fc998ea
commit
1b81888347
11 files changed
+425
-19
No files matched your search
@@ -0,0 +1,278 @@
|
||||
{
|
||||
"task": "REL-02",
|
||||
"sourceCommit": "e54fc998ea711f686143be73b82945cf3c719442",
|
||||
"capturedAt": "2026-09-15T17:51:35.519Z",
|
||||
"node": "v24.21.0",
|
||||
"yarn": "1.22.22",
|
||||
"preparation": {
|
||||
"command": "yarn test:package --browser",
|
||||
"seconds": 106.36,
|
||||
"report": {
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/report.json",
|
||||
"sha256": "3b1f8ff09fb6f3d5c68783406c8c2922570f4592f8212d20ed1f7218a9c6d877"
|
||||
},
|
||||
"log": {
|
||||
"path": "refactor/.cache/rel02-candidates-package.log",
|
||||
"sha256": "7456f57c2ebdc7782a3030a775a64b2baa1f43e733869e79dfe7ec82908f8a9d"
|
||||
},
|
||||
"packages": 20,
|
||||
"runtimeScope": [
|
||||
"artplayer",
|
||||
"artplayer-plugin-chapter"
|
||||
],
|
||||
"runtimeChecks": 36,
|
||||
"legacyTypeModes": 5,
|
||||
"accurateTypeModes": 8,
|
||||
"additionalTypeScope": [
|
||||
"artplayer-plugin-audio-track",
|
||||
"artplayer-plugin-hls-control"
|
||||
]
|
||||
},
|
||||
"thumbnail": {
|
||||
"commands": [
|
||||
"yarn build artplayer-tool-thumbnail",
|
||||
"yarn test:thumbnail-types-package"
|
||||
],
|
||||
"buildSeconds": 1.66,
|
||||
"consumerSeconds": 11.96,
|
||||
"compilerCases": 12,
|
||||
"report": {
|
||||
"path": "refactor/.cache/thumbnail-package-types-rCbvkz/report.json",
|
||||
"sha256": "4b793ffa328d8630ff9d039b80bbb0f68f7e4d865bbbb5ecb1128a77c44cac12"
|
||||
},
|
||||
"logs": [
|
||||
{
|
||||
"path": "refactor/.cache/rel02-candidates-thumbnail-build.log",
|
||||
"sha256": "4cab99627eb04a08b9a6342d61aae2934b2c3df63388843f0857444026d51133"
|
||||
},
|
||||
{
|
||||
"path": "refactor/.cache/rel02-candidates-thumbnail.log",
|
||||
"sha256": "8e011afb610cb18e5118fc4e83f7167908d42e9c91c72f643219a2f4fb219717"
|
||||
}
|
||||
]
|
||||
},
|
||||
"browser": {
|
||||
"command": "yarn test:browser:installed danmuku-timing-diagnostic.spec.js audio-buffering.spec.js --grep \"pending|sampling|sample|timing|held\"",
|
||||
"artifactMap": {
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/browser-artifacts.json",
|
||||
"sha256": "bf0ca0fdfd6f1aa336f7abe65e4bb2225b959ff1dfd15c8902438bbf2f3a967b"
|
||||
},
|
||||
"stats": {
|
||||
"startTime": "2026-09-15T17:44:46.263Z",
|
||||
"duration": 52819.146,
|
||||
"expected": 36,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"report": {
|
||||
"path": "refactor/.cache/rel02-candidates-browser/report.json",
|
||||
"sha256": "67aa867dec7eedaa006df3cc1b332d0685b1147a8160d1c167c8d1e076002641"
|
||||
},
|
||||
"invocation": {
|
||||
"path": "refactor/.cache/rel02-candidates-browser/invocation.json",
|
||||
"sha256": "f70fc5e116621af3c021c31ff5b6ac3b419b0f15c3a0ec007c55a293e30bdeb3"
|
||||
},
|
||||
"result": {
|
||||
"path": "refactor/.cache/rel02-candidates-browser/result.json",
|
||||
"sha256": "0132d84089bcff324bda8625ed72010ef60e2fbc3b6def23d5a75dcf512527d0"
|
||||
},
|
||||
"scope": "24 Danmuku native sampling/eligibility cases plus 12 Audio held-switch cases in three desktop engines; no native starvation closure"
|
||||
},
|
||||
"inputReports": [
|
||||
{
|
||||
"path": "refactor/.cache/release-ledger-G9z39H/report.json",
|
||||
"sha256": "2e6b4993cd79e0c97d62b51376fb4e891c03ea549030e1741eb0626620a2d58b"
|
||||
},
|
||||
{
|
||||
"path": "refactor/.cache/release-ledger-HnUiNG/report.json",
|
||||
"sha256": "c9bc1cce17336957e5de7b94cea3ae80350b396a3197dcb4f80b08dee158b85f"
|
||||
}
|
||||
],
|
||||
"failure": {
|
||||
"actualArchive": "refactor/.cache/packages/run-xQsBHN/artplayer.tgz",
|
||||
"error": "Invalid archive path: package",
|
||||
"collectionLog": {
|
||||
"path": "refactor/.cache/rel02-candidates-provenance.log",
|
||||
"sha256": "1795db66a068399de6798c3b536a7c51ceca8b76768b6542a5bbc18430e40355"
|
||||
},
|
||||
"regressionLog": {
|
||||
"path": "refactor/.cache/rel02-yarn-archive-before.log",
|
||||
"sha256": "9ac61668623d0867e33cd8d82da544a3c51570e097916474cd91aaaee6bb07c1"
|
||||
},
|
||||
"regressionExitCode": 1
|
||||
},
|
||||
"correctedChecker": {
|
||||
"actualArchives": [
|
||||
{
|
||||
"name": "artplayer",
|
||||
"version": "6.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer.tgz",
|
||||
"sha256": "a9913669915970ec5070a4ed80a60ab885624cde7641265e350c07bee1f7ae9c",
|
||||
"integrity": "sha512-tcg5Z64NAiVg2NyzZ/UvxIe1Q9gxG5NCHPVbnBaXukGDt7FUzDo1fUekUhzJtMZUKv0227WMtD968sRfvAy8Sw=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-chapter",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-chapter.tgz",
|
||||
"sha256": "bd5b9d0d467bbd06fb2e60058d27f392bdf62a4ad2f5978cf0ce39fc1bba4ac1",
|
||||
"integrity": "sha512-kw31aC1S+rT+DSC5PGsbwjli26pRJy/5PL75GLYbq8P+9ORm4p3xO3JHiM33qyg0PArckP3NSfNWuxNXVzLGJA=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-ambilight",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-ambilight.tgz",
|
||||
"sha256": "c70002b5ef9260db5aa378360f25bcb3f547b65156182314ecefece7dad8ec49",
|
||||
"integrity": "sha512-u8Sid+prhTO9muhdj4L1A5sacrAcD7yHQbhccIioaZVLZg+uNi6CLn/9yooPsYkgjIVU/2jeqkGCLbIf22602A=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-proxy-canvas",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-proxy-canvas.tgz",
|
||||
"sha256": "5ae7532d29ccdac3114ccb40dab7ea18e024c38d0ea6fa8425571954aee180f6",
|
||||
"integrity": "sha512-HH57q3Qhr2Fq1B8KlU6BKCHtSRxDAyHIv1n4SqzhPYxsU9JTN14UlqnA9tSuMTmf5W0qUslkXVdzzSI9z/Svtg=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-document-pip",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-document-pip.tgz",
|
||||
"sha256": "e06b96ebd9f500b2ba14fb20dcc3ff85643e7c17b93c1a092130c520a23226db",
|
||||
"integrity": "sha512-ONGOJAoFxM/uSXoZzrV7UaqNbnTekS9CU58uR6GuUKsP/miaav4ZLQKTdnET2QUdOZDmt6H9aZzV7/UEMqnBNA=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-ads",
|
||||
"version": "3.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-ads.tgz",
|
||||
"sha256": "8227e59b9a33545964af42b1520763132ef0c6531d81564ea871d0fb6403191c",
|
||||
"integrity": "sha512-duNwmozO5vwKaS0qnk2r9cmMTVabL1nsGZVV/eFq36tWShLVzq+ZGbCGPiGtXqlMORwf0A/PzKMg9DAaL95vKg=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-audio-track",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-audio-track.tgz",
|
||||
"sha256": "0cd3c0b7e380880afcc8fc47af2e3274e7cf6d459e22d8e5d59a20b1f6b48c1d",
|
||||
"integrity": "sha512-5DKXPYVMM8EbXGTCVShGOxyKTPhR4qv6YdIPprmQJ9ovnrCZOorMm6aATwH36GcZ5uxvftL0/19YwaarCEheag=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-vtt-thumbnail",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-vtt-thumbnail.tgz",
|
||||
"sha256": "dab10ac4273ff19572e98218b43cb295b6b86ab6f3e58c5ed3a082b51951cd8a",
|
||||
"integrity": "sha512-QBePktREdD7UEkv/7s8JsVpFelM/ZY6GP10WWL/2R5O97C/BiKGOqFreY0IAjzoXwgNy2WmTDcCwkPw5tMq+vQ=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-multiple-subtitles",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-multiple-subtitles.tgz",
|
||||
"sha256": "4ef6783ebfa8b99ad770c2f922f3d7f4f5835148c3c560a43e90e2237cf6f0e7",
|
||||
"integrity": "sha512-Jp8zkuKlZzgOZr859VEKy9rJgKF9agN4mc1YaOFOdXK/CTWPugvk1BwUkpTYdHvV4BPsXWT3LGF/JKDqsPyhAw=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-hls-control",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-hls-control.tgz",
|
||||
"sha256": "5b87ad54604a6f084c2af7adf9edba004f0a4760efe2ca30f422fb02fd92f188",
|
||||
"integrity": "sha512-VCJh4S9P+PnpWdees2a3j5Q29y8CMBiUwX92Zjcj1UrKjLfn6L9hFcvr+5Rc2bEMu+up+Qwcc7JbQqrBs+NXnA=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-dash-control",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-dash-control.tgz",
|
||||
"sha256": "22885a9df3d00703ec4cc044ac55bb62738f24029b1ae4649139376ef2fbc6f1",
|
||||
"integrity": "sha512-P9KwbaW4yOhHswJNkSgkxg9ZeXVGducq2dq9F/NjuxeqO/AipWDIUP924RBDbDjyc7XDQKQ6WALV8HUqyeWEGQ=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-auto-thumbnail",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-auto-thumbnail.tgz",
|
||||
"sha256": "74ad1f31633da4614458c64ee47a8e43707ada7f79191356928f530fefd8a6d9",
|
||||
"integrity": "sha512-OdpEqH39pAT94qBZ9f1wmPIxmmWvo5dLqIvztLU9hsOpX8luuuyxWa9ShCNq55PGggberAXMvGbfzk1p9dISag=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-asr",
|
||||
"version": "3.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-asr.tgz",
|
||||
"sha256": "9b224b8a5e3ab6bf8a020102311b6e4781bdbb8c996a7d1a641404672f94ad6a",
|
||||
"integrity": "sha512-2jLnZ8JJJ0k0fE8mAxW3vXcQPVGz/yRUpFcVARELvBF0JEgEmzVix+G2zpKaloQrZru8nliw0gBmuTQczNBrXA=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-chromecast",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-chromecast.tgz",
|
||||
"sha256": "025de33f82160a136dba4abcf9024a26c0a663c2745bbdb8b9cbb77dfdfc9eda",
|
||||
"integrity": "sha512-eP+lmJ3hulu5sBVPCSZI+Ll7nxAFQ/UTcIMoPVA9hIxhzn1APAMkOXUBjBjyrkiwdb8oU664Umbys4BRCPBbyg=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-proxy-mediabunny",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-proxy-mediabunny.tgz",
|
||||
"sha256": "42d28808395d04cbb1839525e068680fbba935a1fa0cc21796d46503c2b6d620",
|
||||
"integrity": "sha512-0Feras8kJkaXME9Pq17d5HGFwjIfkSVyULFnFwWakfPBn234Vm0EfPT17GbbE/aPFXcDMCcorbs/TcAt+rwcgQ=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-jassub",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-jassub.tgz",
|
||||
"sha256": "27c9252c0ea648c3e835d7f08d10ca7df04ecda9eec66dbfdb4c45a59b806986",
|
||||
"integrity": "sha512-6y/IJzxtwX6vjxd2kpEkoSFGOwyB9CkGfexZjb5gmJS4A5nuWnswUYYAKK1NhoD6U+KNgQOHvQ1xlBa11Bv2MQ=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-danmuku",
|
||||
"version": "6.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-danmuku.tgz",
|
||||
"sha256": "cd679867754432d4d7129a72eb673cbaec40aac122dad033ff23239580990446",
|
||||
"integrity": "sha512-zL/I+nCxg+BsuhNhcN4nbB/rQkeaxstsNRGJ5a6mr3HWfBwfs8tkMmAsYf+EvE3YECODnmBcVvlLyUDYhmejbg=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-danmuku-mask",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-danmuku-mask.tgz",
|
||||
"sha256": "d82ccc30f91d44bc25c79bdb21975f48bd724c52bff01181755da630de020e4d",
|
||||
"integrity": "sha512-LIcKv9Ny6Ts3g0/BEes4prGliqrr2XytTLh2u04hyZCdDAFPhUKPIGOtKPnojUrpd9DPX5i0bRv067DuXqyYVA=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-tool-iframe",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-tool-iframe.tgz",
|
||||
"sha256": "66adbe3dd7d9a5a0f9c42e2ffbc98a97677e9d410353c671ce046bcad31ffb45",
|
||||
"integrity": "sha512-8be0ck6LtxZQqjHMTeLVFOOo2eq1yL5rLASEVuZK7z9/CVaBl2hoatAuOnMRD8QloE58nL3a+J4mbrH10vX0mQ=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-vast",
|
||||
"version": "2.0.0",
|
||||
"path": "refactor/.cache/packages/run-xQsBHN/artplayer-plugin-vast.tgz",
|
||||
"sha256": "ab0b1d57e7c12a9f77679e5a57bf424a47b3498fa0cff20551036d387eb7043d",
|
||||
"integrity": "sha512-rp/ZfsPIGCPr7dvR369tg72bQn9M9iVARcL2Axo+u+CuO976LhBhk+hteUeFs1NpQDwB745ZzyCtNS8Ap3ITTA=="
|
||||
},
|
||||
{
|
||||
"name": "artplayer-tool-thumbnail",
|
||||
"version": "5.0.0",
|
||||
"path": "refactor/.cache/thumbnail-package-types-rCbvkz/candidate.tgz",
|
||||
"sha256": "6eea43186a3020f12a463fc4cdef3dc9972ed1cbc04f2cad5c158054e51cf459",
|
||||
"integrity": "sha512-FUGZyHcM3ZyIGAKU0fRX8HJot+56fU+zntCp0fuBR08I5yCpuf943uHH35roLp7NYJbzC8qlGaq2eIdXlaEb2A=="
|
||||
}
|
||||
],
|
||||
"passed": 21,
|
||||
"regressionTests": {
|
||||
"passed": 80,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"durationMs": 2774.1443,
|
||||
"log": {
|
||||
"path": "refactor/.cache/rel02-yarn-archive-after.log",
|
||||
"sha256": "b4abe3606cb95409a64e7e1c33f87120e875c5e4bd75d3d1756746562ff7f663"
|
||||
}
|
||||
},
|
||||
"checks": [
|
||||
"targeted ESLint exit 0",
|
||||
"tsc -p scripts/tsconfig.release.json --noEmit exit 0"
|
||||
]
|
||||
},
|
||||
"limitations": [
|
||||
"These build/browser reports preceded the archive-checker correction and are not rebound to its new fingerprint.",
|
||||
"All 21 archives are accepted by the corrected content checker, but no candidate or release gate has been registered.",
|
||||
"The only before/after input change was the browser-generated docs/uncompiled/artplayer-plugin-danmuku/index.js, affecting site inputs only; library fingerprints were unchanged until the checker fix.",
|
||||
"Complete combinations, physical devices, rollback, remote CI and user-guided formal reviews remain open."
|
||||
],
|
||||
"publicationAuthorized": false
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# REL-02 checkpoint: accept actual Yarn candidate archives
|
||||
|
||||
The 20-package browser preparation on source commit
|
||||
`e54fc998ea711f686143be73b82945cf3c719442` passed in 106.36 seconds.
|
||||
It built in an isolated snapshot, packed and installed the target majors,
|
||||
verified frozen consumer locks and installed members, and ran the core/Chapter
|
||||
36 runtime checks, 5 legacy and 8 accurate type modes, plus Audio/HLS fixtures.
|
||||
Thumbnail 5.0.0 was built separately and passed its 12 historical/candidate
|
||||
compiler cases. This is not all-plugin runtime or type acceptance.
|
||||
|
||||
Using the actual 20-package installed map, the focused desktop Chromium,
|
||||
Firefox and Windows WebKit run passed 36 tests with zero retries, failures or
|
||||
skips: 24 Danmuku sampling/eligibility cases and 12 Audio held-switch cases.
|
||||
The native starvation failures, other combinations and physical device gaps
|
||||
remain open. Windows WebKit does not establish physical Safari behavior.
|
||||
|
||||
Candidate registration then exposed a real checker defect: Yarn writes its
|
||||
root and nested directory entries as `package` and `package/dist`, without
|
||||
trailing slashes. `checkedCandidate` incorrectly used the historical archive
|
||||
inventory helper, which rejected the root as `Invalid archive path: package`.
|
||||
No candidate was registered and no release gate was bypassed.
|
||||
|
||||
The type-aware tar listing logic already used by isolated installation is now
|
||||
in `scripts/package-archive.mjs`. Both installation and candidate registration
|
||||
use it; `scripts/package-check.mjs` retains its existing `packedFiles` export.
|
||||
The helper accepts directory entries with or without trailing slashes and
|
||||
rejects links, special files, duplicate members, wrong roots and traversal.
|
||||
Historical archive inventory remains unchanged. No dependency, package API,
|
||||
runtime implementation or npm entry changed.
|
||||
|
||||
A self-contained tar fixture reproduces Yarn's directory layout. It failed
|
||||
before the fix, and checks both accepted directory forms plus hard links,
|
||||
symlinks, FIFO entries, a regular-file root, duplicates and invalid paths after
|
||||
the fix. The combined ledger/bundle/verifier/package tests passed 80/80 in
|
||||
2774.1443 ms; targeted lint and strict release TypeScript checks passed.
|
||||
The corrected checker also accepted all 21 actual prepared archives, checking
|
||||
their recorded SHA-256, SHA-512, manifest names and target versions.
|
||||
|
||||
Detailed reports, logs, immutable archive bindings and the preserved browser
|
||||
report are indexed in [the validation record](../baselines/major-candidate-archive-validation.json).
|
||||
Before/after library input fingerprints were unchanged during preparation.
|
||||
The browser server generated a Danmuku development bundle, changing only the
|
||||
site input inventory. The archive-checker correction subsequently changed
|
||||
shared validation inputs, so the earlier build/browser results are retained
|
||||
as observed and are not rebound to the new fingerprint.
|
||||
|
||||
REL-02 remains doing. Commit this checker correction before rebuilding and
|
||||
registering candidates with its exact committed validation inputs. Candidate
|
||||
registration, complete combinations and candidate-specific rollback remain
|
||||
unfinished. Reverting this checkpoint restores the incorrect Yarn rejection;
|
||||
existing historical reports remain available. No formal review, remote write,
|
||||
deployment or publication was performed.
|
||||
+1
-1
@@ -698,7 +698,7 @@
|
||||
- REL-08: [记录](changes/2026-09-14-REL-08-release-ledger.md) [记录](baselines/release-ledger-validation.json) [记录](release-ledger.md) [记录](release-ledger.json)
|
||||
- REL-01: [记录](version-plan.md) [记录](version-plan.json) [记录](baselines/version-registry-2026-09-16.json) [记录](changes/2026-09-16-REL-01-version-plan.md)
|
||||
- REL-09: [记录](changes/2026-09-16-REL-09-major-versions.md) [记录](baselines/major-version-preparation.json) [记录](baselines/version-registry-prepared-2026-09-16.json) [记录](version-plan.md)
|
||||
- REL-02: [记录](changes/2026-09-16-REL-02-types-inputs.md) [记录](baselines/major-installed-types-validation.json)
|
||||
- REL-02: [记录](changes/2026-09-16-REL-02-types-inputs.md) [记录](baselines/major-installed-types-validation.json) [记录](changes/2026-09-16-REL-02-yarn-candidate-archives.md) [记录](baselines/major-candidate-archive-validation.json)
|
||||
- REL-04: [记录](changes/2026-09-15-REL-04-consumer-checkpoint.md) [记录](rollback-rehearsal.md) [记录](baselines/rollback-consumer-validation.json) [记录](changes/2026-09-15-REL-04-workflows-checkpoint.md) [记录](rollback-inventory.md) [记录](baselines/rollback-workflows-validation.json) [记录](changes/2026-09-15-REL-04-pages-recovery.md) [记录](baselines/pages-recovery-validation.json) [记录](changes/2026-09-15-REL-04-acceptance.md) [记录](baselines/rollback-acceptance-validation.json)
|
||||
- PKG-FACTORY-01: [记录](baselines/factory-assignment-gaps.json) [记录](baselines/factory-compatibility-proposals.json) [记录](factory-compatibility-decision.md) [记录](changes/2026-09-12-PKG-FACTORY-01-decision.md) [记录](type-compatibility-policy.md) [记录](baselines/factory-compatibility-validation.json) [记录](changes/2026-09-13-PKG-FACTORY-01-compatible-types.md)
|
||||
- CORE-25: [记录](changes/2026-09-13-CORE-25-defaults-ssr.md) [记录](baselines/defaults-ssr-validation.json)
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# 进度与证据
|
||||
|
||||
## REL-02 Yarn候选归档检查修复
|
||||
|
||||
统一20包构建/隔离安装通过,Thumbnail单独构建及12组类型消费通过;实际安装
|
||||
产物的弹幕采样24项和Audio等待顺序12项三浏览器回归全部通过,保留原断流缺口。
|
||||
登记时发现发布校验器误拒绝Yarn无尾斜杠目录,现与安装流程共用条目类型校验,
|
||||
80项相关测试、lint及严格TS通过,并实际接受21个归档。见[记录](changes/2026-09-16-REL-02-yarn-candidate-archives.md)
|
||||
和[证据](baselines/major-candidate-archive-validation.json)。此前产物报告不套用修复后
|
||||
的新指纹;下一步固定提交再准备登记候选。REL-02仍doing,数量224/21/40不变。
|
||||
未启动用户保留的复盘,也没有推送、远端派发、部署或发布。
|
||||
|
||||
## REL-02 全包安装类型验证与输入指纹修复
|
||||
|
||||
21个库的18组隔离消费命令全部通过,包含核心、所有插件/proxy/工具的目标major
|
||||
|
||||
@@ -65,6 +65,10 @@ site-manifest文件包含package、version、outputRoot和files,每个file为p
|
||||
outputRoot必须在仓库内;目录完整文件集须等于files,新增、缺失、替换或符号链接输出
|
||||
均拒绝。清单SRI和每个实际部署文件字节分别验证;URL正确性仍必须有site-urls报告。
|
||||
|
||||
候选tar成员检查与隔离安装共用scripts/package-archive.mjs,按实际条目类型识别
|
||||
目录,接受Yarn pack生成的无尾斜杠package和子目录;拒绝链接、特殊文件、重复
|
||||
成员和越界路径。冻结历史archive的原校验器仍用于历史内容核对,不用于新候选。
|
||||
|
||||
`inputFingerprint`包含本包、其实际依赖闭包,以及共享构建/工具链/测试/CI输入。
|
||||
依赖来自impact-model的显式关系和源码/声明/manifest扫描;未解释动态导入按全部包
|
||||
保守处理。站点还包含docs及example。第三方清单、本校验器、兼容/环境/版本/复盘
|
||||
|
||||
@@ -5,9 +5,10 @@ import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||
import { parseArgs } from 'node:util'
|
||||
import { packedFiles } from '../../scripts/package-archive.mjs'
|
||||
import { readImpactModel, repositoryPath } from './impact-model.mjs'
|
||||
import { dependencyClosure, evaluatePackage, findingPackages, validateLedger } from './release-ledger-model.mjs'
|
||||
import { archiveFiles, hash, readMember } from './releases.mjs'
|
||||
import { hash, readMember } from './releases.mjs'
|
||||
|
||||
export const root = fileURLToPath(new URL('../../', import.meta.url))
|
||||
|
||||
@@ -74,7 +75,7 @@ export function checkedCandidate(directory, row) {
|
||||
}
|
||||
else {
|
||||
assert.equal(binding.kind, 'npm-tarball')
|
||||
archiveFiles(artifact)
|
||||
packedFiles(artifact)
|
||||
const manifest = JSON.parse(readMember(artifact, 'package/package.json'))
|
||||
assert.equal(manifest.name, row.name, 'Tarball package name mismatch')
|
||||
assert.equal(manifest.version, binding.version, 'Tarball version mismatch')
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { Buffer } from 'node:buffer'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Release evidence must fail closed under stale or mis-scoped input.
|
||||
import test from 'node:test'
|
||||
import { gzipSync } from 'node:zlib'
|
||||
import { dependencyClosure, evaluatePackage, findingPackages, libraryGates, sharedTasks, siteGates, validateLedger } from './release-ledger-model.mjs'
|
||||
import { checkedCandidate, checkedReport, fingerprintInputs, fingerprintOf, localFile, root } from './release-ledger.mjs'
|
||||
import { hash } from './releases.mjs'
|
||||
@@ -218,3 +220,49 @@ test('Release candidate checks actual tarball manifest and detects digest/versio
|
||||
save('candidate.tgz', 'tampered')
|
||||
assert.match(checkedCandidate(directory, row).errors[0], /Candidate integrity mismatch/)
|
||||
})
|
||||
|
||||
function candidateArchive(entries) {
|
||||
const blocks = []
|
||||
for (const { name, type = '0', content = '', link = '' } of entries) {
|
||||
const bytes = Buffer.from(content)
|
||||
const header = Buffer.alloc(512)
|
||||
header.write(name)
|
||||
header.write('0000755\0', 100)
|
||||
header.write('0000000\0', 108)
|
||||
header.write('0000000\0', 116)
|
||||
header.write(`${bytes.length.toString(8).padStart(11, '0')}\0`, 124)
|
||||
header.write('00000000000\0', 136)
|
||||
header.fill(32, 148, 156)
|
||||
header.write(type, 156)
|
||||
header.write(link, 157)
|
||||
header.write('ustar\0', 257)
|
||||
header.write('00', 263)
|
||||
header.write(`${header.reduce((sum, byte) => sum + byte, 0).toString(8).padStart(6, '0')}\0 `, 148)
|
||||
blocks.push(header, bytes, Buffer.alloc((512 - bytes.length % 512) % 512))
|
||||
}
|
||||
return gzipSync(Buffer.concat([...blocks, Buffer.alloc(1024)]))
|
||||
}
|
||||
|
||||
test('Release candidate accepts Yarn directory entries without trailing slashes and rejects unsafe entry types', (t) => {
|
||||
const { directory, save } = temp(t)
|
||||
execFileSync('git', ['init', '-q', directory])
|
||||
execFileSync('git', ['-c', 'user.name=Ledger test', '-c', 'user.email=ledger@example.invalid', 'commit', '--allow-empty', '-qm', 'fixture'], { cwd: directory })
|
||||
const sourceCommit = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: directory, encoding: 'utf8' }).trim()
|
||||
const manifest = { name: 'example', version: '2.0.0' }
|
||||
const entries = [{ name: 'package', type: '5' }, { name: 'package/dist', type: '5' }, { name: 'package/package.json', content: JSON.stringify(manifest) }, { name: 'package/dist/index.js', content: 'export default 1' }]
|
||||
const row = { name: manifest.name, distribution: 'npm', candidate: { kind: 'npm-tarball', path: 'candidate.tgz', version: manifest.version, sourceCommit } }
|
||||
const verify = (members) => {
|
||||
const bytes = candidateArchive(members)
|
||||
save('candidate.tgz', bytes)
|
||||
row.candidate.integrity = `sha512-${hash(bytes, 'sha512', 'base64')}`
|
||||
return checkedCandidate(directory, row).errors
|
||||
}
|
||||
assert.deepEqual(verify(entries), [])
|
||||
assert.deepEqual(verify(entries.map(entry => entry.type === '5' ? { ...entry, name: `${entry.name}/` } : entry)), [])
|
||||
for (const type of ['1', '2', '6'])
|
||||
assert.match(verify([...entries, { name: 'package/dist/link.js', type, link: 'package/dist/index.js' }])[0], /links and special files/)
|
||||
assert.match(verify([{ name: 'package', content: 'not a directory' }, ...entries.slice(1)])[0], /Invalid package root/)
|
||||
assert.match(verify([...entries, entries[2]])[0], /Duplicate archive members/)
|
||||
assert.match(verify([...entries, { name: 'outside.json', content: '{}' }])[0], /Invalid package root/)
|
||||
assert.match(verify([...entries, { name: 'package/../outside.json', content: '{}' }])[0], /Unsafe package member/)
|
||||
})
|
||||
+3
-1
@@ -5015,7 +5015,9 @@
|
||||
"acceptance": "隔离安装和可自动化组合通过;设备结论不伪造,最终发布绑定同一候选内容;在目标 major 版本确定后构建 pack,不在测试后改版本;逐包核验完整回退产物、实际候选版本/integrity、应用导入与冻结锁,重跑对应回退并保留报告;缺失历史分发不准入",
|
||||
"evidence": [
|
||||
"changes/2026-09-16-REL-02-types-inputs.md",
|
||||
"baselines/major-installed-types-validation.json"
|
||||
"baselines/major-installed-types-validation.json",
|
||||
"changes/2026-09-16-REL-02-yarn-candidate-archives.md",
|
||||
"baselines/major-candidate-archive-validation.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
|
||||
export function packedFiles(archive) {
|
||||
const args = { encoding: 'utf8', windowsHide: true }
|
||||
const names = execFileSync('tar', ['-tzf', archive], args).trim().split(/\r?\n/)
|
||||
const entries = execFileSync('tar', ['-tvzf', archive], args).trim().split(/\r?\n/)
|
||||
assert.equal(names.length, entries.length, 'Archive listing mismatch')
|
||||
assert.equal(new Set(names).size, names.length, 'Duplicate archive members')
|
||||
return names.filter((name, index) => {
|
||||
const type = entries[index][0]
|
||||
assert(['d', '-'].includes(type), 'Package links and special files are unsupported')
|
||||
assert((type === 'd' && name === 'package') || name.startsWith('package/'), 'Invalid package root')
|
||||
assert(!name.includes('\\') && !name.split('/').includes('..'), 'Unsafe package member')
|
||||
return type === '-'
|
||||
}).sort()
|
||||
}
|
||||
@@ -7,8 +7,11 @@ import { fileURLToPath } from 'node:url'
|
||||
import { ensureArchive, hash, readMember } from '../refactor/scripts/releases.mjs'
|
||||
import { installedPackages } from './browser-validation/scope.ts'
|
||||
import { installedPluginTypes } from './consumers/packages.ts'
|
||||
import { packedFiles } from './package-archive.mjs'
|
||||
import { consumerDirectory, names as defaultNames, readJson, removeConsumer, run, runtimeConsumer, typeConsumers, workspace, writeJson } from './package-consumer.mjs'
|
||||
|
||||
export { packedFiles } from './package-archive.mjs'
|
||||
|
||||
export function packageOptions(args) {
|
||||
assert(args.every(arg => ['--release', '--browser'].includes(arg) || arg.startsWith('--include=')), 'Unknown package-check option')
|
||||
const includes = args.filter(arg => arg.startsWith('--include='))
|
||||
@@ -60,21 +63,6 @@ export function historicalDistributionFiles(name, { baseline, sources }) {
|
||||
return members
|
||||
}
|
||||
|
||||
export function packedFiles(archive) {
|
||||
const args = { encoding: 'utf8', windowsHide: true }
|
||||
const names = execFileSync('tar', ['-tzf', archive], args).trim().split(/\r?\n/)
|
||||
const entries = execFileSync('tar', ['-tvzf', archive], args).trim().split(/\r?\n/)
|
||||
assert.equal(names.length, entries.length, 'Archive listing mismatch')
|
||||
assert.equal(new Set(names).size, names.length, 'Duplicate archive members')
|
||||
return names.filter((name, index) => {
|
||||
const type = entries[index][0]
|
||||
assert(['d', '-'].includes(type), 'Package links and special files are unsupported')
|
||||
assert((type === 'd' && name === 'package') || name.startsWith('package/'), 'Invalid package root')
|
||||
assert(!name.includes('\\') && !name.split('/').includes('..'), 'Unsafe package member')
|
||||
return type === '-'
|
||||
}).sort()
|
||||
}
|
||||
|
||||
export async function publishedConsumer() {
|
||||
const dir = consumerDirectory()
|
||||
const releases = readJson(path.join(workspace, 'refactor/baselines/releases.json')).releases
|
||||
|
||||
@@ -28,6 +28,12 @@ reports are not evidence that an ArtPlayer package is ready to publish.
|
||||
|
||||
## Responsibilities
|
||||
|
||||
- `../package-archive.mjs` checks actual tar entry types and paths for both
|
||||
package installation checks and candidate registration. It accepts Yarn's
|
||||
directory entries without a trailing slash while rejecting links, special
|
||||
files, duplicate members and paths outside `package/`. The legacy
|
||||
`package-check.mjs` export forwards to this helper for existing scripts.
|
||||
|
||||
- `../prepare-release.mjs` is the Node entry and failure exit-code boundary.
|
||||
- `prepare.ts` parses the explicit package batch/tag, requires the canonical
|
||||
Node/Yarn, and checks clean Git state before both ledger reads. Ignored generated
|
||||
|
||||
Reference in new issue
Block a user