diff --git a/refactor/baselines/README.md b/refactor/baselines/README.md index 99a228d2e..67ad00adf 100644 --- a/refactor/baselines/README.md +++ b/refactor/baselines/README.md @@ -1,5 +1,9 @@ # 已发布基线 +PKG-HLS-01 另行固定 HLS control 1.1.0,见 [契约](hls-control-contract.md) 与 +[归档指纹](hls-control-release.json)。重跑 `node refactor/scripts/hls-contract.mjs`; +它验证独立冻结记录及历史源码,不改下方 BASE-01 数据,也不表示 HLS 真实播放已通过。 + BASE-01 于 2026-09-10 固定核心与 chapter 的 npm 发布内容,数据在 [releases.json](releases.json)。这不是全生态兼容通过报告。 | 包 | 工作区版本 | 已固定发布基线 | 后续目标 | diff --git a/refactor/baselines/hls-control-contract.md b/refactor/baselines/hls-control-contract.md new file mode 100644 index 000000000..a48711671 --- /dev/null +++ b/refactor/baselines/hls-control-contract.md @@ -0,0 +1,63 @@ +# HLS control 1.1.0 迁移契约 + +PKG-HLS-01,2026-09-11。发布依据是 [冻结归档记录](hls-control-release.json),源码依据为 +adec20213f00375b16231e616d1e249a12ffd345,示例为 docs/assets/example/hls.control.js。 +运行 `node refactor/scripts/hls-contract.mjs` 重验,不随迁移覆盖历史指纹。 + +## 发布与来源 + +固定 npm artplayer-plugin-hls-control 1.1.0:SHA-512 SRI、SHA-256、六个成员及各成员摘要均已验证。 +README、package.json、声明经 LF 归一化与该提交相同。TypeScript 5.9.3 提取 uniqBy 和 +artplayerPluginHlsControl 后用 esbuild 0.27.7 归一化,两边 SHA-256 同为 +`b22a09f4de5b56005c5122014624d76a91410e9517889d3e7b1c70b8efb2b554`。 +比较不含 SVG 字符串或 bundler 包装,不等于用现有工具链逐字重建所有发布文件。 + +查询时 registry 列出 1.0.0、1.0.1、1.1.0,latest 为 1.1.0;时间与 URL 保存在 JSON。 +登记的 gitHead daf133b22630b4a0eecfa3336bbddab0e9119d96 对应包版本 1.0.2,不能当作 +发布源码证明。计划版本 2.0.0,发布前另查版本占用。旧版行为以 tarball 为准。 + +## 公开边界及测试入口 + +| ID | 当前行为与兼容要求 | 后续覆盖 | +| --- | --- | --- | +| HLS.factory | default/global 为 artplayerPluginHlsControl;工厂默认参数 `{}`,返回同步注册函数 | HLS-02 各格式消费、无参调用 | +| HLS.result | 注册返回 `{ name: 'artplayerPluginHlsControl', update }`;update 无参、同步返回 undefined | HLS-02 返回与键集合 | +| HLS.binding | 注册捕获 template.$video;每次 update 检查 art.hls.media 与它同一引用,失败通过 errorHandle 抛出 Cannot find instance of HLS from "art.hls" | HLS-02 缺失/外部媒体/替换实例 | +| HLS.schedule | 注册时不执行 update;订阅 ready 和 restart,外加公开手动 update;未订阅 Hls SDK 事件 | HLS-02 调用顺序;HLS-03 补同步与解绑 | +| HLS.option | quality/audio 均可选,子项 control/setting/title/auto/getName;两个显示开关默认关闭,update 仍验证 Hls | HLS-02 默认、单独和同时启用 | +| HLS.quality | 标签取 name 或 height 加 P;按标签保留第一个,按原索引倒序;最后追加 Auto value=-1;选中项依据 currentLevel | HLS-02 重复/排序/Auto/manual | +| HLS.audio | 标签取 name/lang/language;按标签保留第一个并维持原顺序;value 为 track.id,不附加 Auto 选项 | HLS-02 标签/排序;HLS-05 实际分组轨道 | +| HLS.label | title/auto 使用逻辑或默认值;当前标签 getName(item) 在列表 getName(item,index) 之前执行;普通函数调用,无 art 上下文绑定 | HLS-02 参数数目、对象身份、回调异常 | +| HLS.select | 先写 currentLevel/audioTrack,再 notice,再按开关 controls.check/setting.check,返回 item.html;不返回 Promise | HLS-02 顺序、值和引用 | +| HLS.ui | 名称 hls-quality/hls-audio;control 在 right,padding 0 10px;setting 宽 200、原 SVG 图标、title 与 tooltip;两处共享 selector/onSelect | HLS-02 对象形状;HLS-05 真 DOM | +| HLS.owner | Hls 由消费者创建/销毁;插件没有公开 destroy,不拥有媒体实例;旧实现没有自身销毁/SDK 解绑逻辑 | HLS-02 销毁观察;HLS-03 整理资源归属 | + +uniqBy 对 undefined 标签不去重;重复标签留下首条,可能移除实际选中的重复条目。 +getName 错误同步传播;质量 UI 可在音轨更新失败前已经提交。不在重构时未经说明改成 +异步回调、绑定 this、克隆 SDK 输入项或全局吞掉异常。 + +保留根入口和 /legacy 的 exports 条件、main/module/types/legacy 路径与全局名。 +包没有 Hls 或核心 dependency/peerDependencies 最低版本声明,不新造最低版本,也不宣称 +任意旧版本都兼容。旧核心 5.4.0 与当前核心的四组合须由 HLS-05 实测;这里只冻结待验证范围。 +示例绑定 Hls.js 1.5.17,此版本是首个 SDK 实测基线,不是已证明的最低/最高支持版本。 + +## 声明、示例与设计差异 + +| 观察 | 依据与边界 | 处理任务 | +| --- | --- | --- | +| 工厂 option 声明必填,运行时可省略 | 局部 Config 未按名称导出;只导出 default | HLS-02 类型复现,HLS-04 兼容修正 | +| getName 声明只接受 object,漏了列表索引 | 当前标签只传一个参数,所以未来索引应可缺省;不能声明总是 number | HLS-02 消费样例,HLS-04 类型 | +| /legacy 缺少旧解析器 typesVersions fallback | exports types 存在不代表 TS 4.3 node 解析可用 | HLS-04/06 解析矩阵 | +| 空 levels/audioTracks 直接返回,关闭显示开关也不删除旧菜单 | 静态可见缺少 controls.remove/setting.remove | HLS-02 复现,HLS-03 修复 | +| 保留旧 selector 回调仍写旧 Hls | 回调捕获上次 update 的实例;公开 update 则读取新 art.hls | HLS-02 复现,HLS-03 限制过期回调 | +| Auto 依据 currentLevel,未使用 autoLevelEnabled | 不能仅用 currentLevel=-1 的 stub 代表实际 ABR;真实播放档位与手动策略分别取证 | HLS-02/05 SDK 实测,HLS-03 改进 | +| 音轨当前标签以数组索引取值,选择值用 id | 不仅凭两种写法不同就认定真实 SDK 错误,须验证 Hls 分组后的 id/index 关系 | HLS-02/05 | +| 示例原生 HLS fallback 未提供 art.hls | customType 中只赋 video.src,插件仍安装;ready 校验可能抛错 | HLS-05 浏览器取证与示例修复 | +| 示例每次切源注册新的 destroy 回调 | 重建时已销毁旧 Hls,旧闭包仍被保留 | HLS-05/06 生命周期及示例修复 | + +README 目前仅简介、demo、许可,不能从中推断未声明的行为。示例同时启用两个菜单,使用 +level.height 和 track.name 回调以及远程 HLS;后续用本地多档位/多音轨样本补确定性验证。 + +本步只核对来源和契约,没有生产代码变更、SDK 播放或浏览器验收。后续结构规划是把选择项 +映射、核心 UI 提交/删除、SDK 状态与订阅、公开兼容入口分开;实际实现地图随 HLS-03/04 +写入包内 ARCHITECTURE.md,不把未实现的设计写成当前架构。 diff --git a/refactor/baselines/hls-control-release.json b/refactor/baselines/hls-control-release.json new file mode 100644 index 000000000..e70f7623f --- /dev/null +++ b/refactor/baselines/hls-control-release.json @@ -0,0 +1,119 @@ +{ + "schemaVersion": 1, + "task": "PKG-HLS-01", + "capturedAt": "2026-09-11T15:21:31.189Z", + "sourceCommit": "adec20213f00375b16231e616d1e249a12ffd345", + "registryObservation": { + "capturedAt": "2026-09-11T15:20:11.198Z", + "registryUrl": "https://registry.npmjs.org/artplayer-plugin-hls-control", + "distTags": { + "latest": "1.1.0" + }, + "versions": [ + "1.0.0", + "1.0.1", + "1.1.0" + ], + "publishedAt": "2026-03-12T14:20:47.883Z", + "note": "Observed metadata only; not a promise of future latest version or target-version availability." + }, + "release": { + "name": "artplayer-plugin-hls-control", + "version": "1.1.0", + "metadataUrl": "https://registry.npmjs.org/artplayer-plugin-hls-control/1.1.0", + "tarball": "https://registry.npmjs.org/artplayer-plugin-hls-control/-/artplayer-plugin-hls-control-1.1.0.tgz", + "integrity": "sha512-lWN5oUOWDorWFHdzKcmy9Z8eHcf5f5EcUGDrxBsZBX7aEL5dGRlHPQ5+wqQEizr38D9PYPfTI/nCyun2yFopEw==", + "sha256": "598c354d78d3cb77965136fa61dfc0f94cdea6906a91a30781c1acef2b0c3e8b", + "archiveBytes": 3192, + "registryGitHead": "daf133b22630b4a0eecfa3336bbddab0e9119d96", + "files": { + "package/README.md": "42bd00dca467b581f6b3e8399ad1a416d68edcc52d42e6cb51b66f1749694556", + "package/dist/artplayer-plugin-hls-control.js": "7a6ce18a0b16f61f6149e0ea77efbb6e0503f997d39afe84271b59e366759e6d", + "package/dist/artplayer-plugin-hls-control.legacy.js": "893a3de27f9ed02b4b61f03732aec03bfcaf50d02c9beb15cc8a5767ef9121a0", + "package/dist/artplayer-plugin-hls-control.mjs": "85c4de4940e031d835b4de3ccf68af449d10aec4f630c89ecaf62f5503348931", + "package/package.json": "710ec2a27dc71f7254e7a1d2eb7cff3f56a6e23811047ac97356f1b18c8ac8b5", + "package/types/artplayer-plugin-hls-control.d.ts": "7dd8fdf556932e9cf6140b7513c05155cad6d486e2484bf06c6d48f6e823832a" + }, + "manifest": { + "name": "artplayer-plugin-hls-control", + "version": "1.1.0", + "description": "Hls control plugin for ArtPlayer", + "author": "Harvey Zhao ", + "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-hls-control.d.ts", + "import": "./dist/artplayer-plugin-hls-control.mjs", + "require": "./dist/artplayer-plugin-hls-control.js" + }, + "./legacy": { + "types": "./types/artplayer-plugin-hls-control.d.ts", + "import": "./dist/artplayer-plugin-hls-control.legacy.js", + "require": "./dist/artplayer-plugin-hls-control.legacy.js" + } + }, + "main": "./dist/artplayer-plugin-hls-control.js", + "module": "./dist/artplayer-plugin-hls-control.mjs", + "types": "./types/artplayer-plugin-hls-control.d.ts", + "legacy": "./dist/artplayer-plugin-hls-control.legacy.js", + "browserslist": "last 1 Chrome version" + } + }, + "source": { + "packages/artplayer-plugin-hls-control/package.json": "710ec2a27dc71f7254e7a1d2eb7cff3f56a6e23811047ac97356f1b18c8ac8b5", + "packages/artplayer-plugin-hls-control/README.md": "42bd00dca467b581f6b3e8399ad1a416d68edcc52d42e6cb51b66f1749694556", + "packages/artplayer-plugin-hls-control/types/artplayer-plugin-hls-control.d.ts": "7dd8fdf556932e9cf6140b7513c05155cad6d486e2484bf06c6d48f6e823832a", + "packages/artplayer-plugin-hls-control/src/index.js": "aa477db8743be2953a23776421edb68566d504c3278269eb13f6e907a4d5f2db", + "packages/artplayer-plugin-hls-control/src/audio.svg": "dbee5ce7487c9f8ec927e5286188cf9439345bbe947b6c06c32c07193e01e0be", + "packages/artplayer-plugin-hls-control/src/quality.svg": "4666a4c01764422f9008e442f5a889ff9691bb0386083d673943a0718f4d680c", + "docs/assets/example/hls.control.js": "b02fd290d79999790501447fad95736642344b9b30af3ccdbe353f80c7d53a6e" + }, + "comparisons": [ + { + "file": "package.json", + "publishedLF": "710ec2a27dc71f7254e7a1d2eb7cff3f56a6e23811047ac97356f1b18c8ac8b5", + "workspaceLF": "710ec2a27dc71f7254e7a1d2eb7cff3f56a6e23811047ac97356f1b18c8ac8b5", + "equal": true + }, + { + "file": "README.md", + "publishedLF": "42bd00dca467b581f6b3e8399ad1a416d68edcc52d42e6cb51b66f1749694556", + "workspaceLF": "42bd00dca467b581f6b3e8399ad1a416d68edcc52d42e6cb51b66f1749694556", + "equal": true + }, + { + "file": "types/artplayer-plugin-hls-control.d.ts", + "publishedLF": "7dd8fdf556932e9cf6140b7513c05155cad6d486e2484bf06c6d48f6e823832a", + "workspaceLF": "7dd8fdf556932e9cf6140b7513c05155cad6d486e2484bf06c6d48f6e823832a", + "equal": true + } + ], + "functionComparison": { + "sha256": "b22a09f4de5b56005c5122014624d76a91410e9517889d3e7b1c70b8efb2b554", + "typescript": "5.9.3", + "esbuild": "0.27.7", + "scope": [ + "uniqBy", + "artplayerPluginHlsControl" + ], + "excludes": [ + "SVG strings", + "bundler wrappers" + ], + "note": "Historical source at sourceCommit, not live migration source." + }, + "provenanceNote": "Registry gitHead daf133b22630b4a0eecfa3336bbddab0e9119d96 has package version 1.0.2; it does not prove tarball source provenance." +} diff --git a/refactor/changes/2026-09-11-PKG-HLS-01-contract.md b/refactor/changes/2026-09-11-PKG-HLS-01-contract.md new file mode 100644 index 000000000..0e63b507f --- /dev/null +++ b/refactor/changes/2026-09-11-PKG-HLS-01-contract.md @@ -0,0 +1,18 @@ +# PKG-HLS-01:固定 HLS control 发布与兼容边界 + +已核对源文件、两个 SVG、声明、README、官方示例以及 npm 1.1.0 六文件归档。 +见 [契约](../baselines/hls-control-contract.md) 和 [指纹](../baselines/hls-control-release.json)。 +单独新增基线,不覆盖 BASE-01 的历史数据。三份元数据相同,两段主逻辑归一化一致, +registry gitHead 的版本不匹配如实登记,不当作源码来源证明。 + +新增只读重验入口 `node refactor/scripts/hls-contract.mjs`,复用归档完整性工具,逐文件验证, +从固定 Git 提交读取历史源码;不要求迁移后的现行源码保持旧实现。没有新增依赖或生产脚本。 +离线缓存可重跑,缓存缺失时仅从固定 registry URL 下载并验 hash。脚本不执行发布代码。 + +结构/类型/兼容:本步冻结工厂、同步 update、媒体绑定、菜单名/形状、getName 调用、选择顺序、 +入口和未声明的支持窗口。空轨道残留、旧回调、Auto、声明遗漏和示例清理分别落到 HLS-02~06。 +未修改生产源码或声明;类型及浏览器行为验证属于后续任务,不以本步静态核对代替。 + +验证:固定归档 SHA-512/SHA-256、六成员 hash、历史源码 hash、三份元数据及两个函数对照通过; +计划检查、基线测试与 Git 差异检查通过。没有运行全量核心播放矩阵,因为本步不改播放器。 +回退本提交只撤回 HLS 契约与重验工具,不影响生产产物。下一步 HLS-02,完成后另行提交。 diff --git a/refactor/plan.md b/refactor/plan.md index 072711a15..629c8b6dc 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -4,7 +4,7 @@ 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 215 项,范围 22 个包及工作区/示例。 -状态:todo 154 / doing 0 / blocked 0 / done 61 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 153 / doing 0 / blocked 0 / done 62 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -188,7 +188,7 @@ | ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | | --- | --- | --- | --- | --- | --- | --- | -| PKG-HLS-01 | artplayer-plugin-hls-control
核对包契约与历史用法 | BASE-05 | quality/audio 配置、getName、update、控件名及 Hls 实例绑定 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo | +| PKG-HLS-01 | artplayer-plugin-hls-control
核对包契约与历史用法 | BASE-05 | quality/audio 配置、getName、update、控件名及 Hls 实例绑定 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done | | PKG-HLS-02 | artplayer-plugin-hls-control
建立特有行为与错误测试 | PKG-HLS-01, ENG-03, ENG-05 | Auto/手动实际 level、音轨、去重/过滤和拓扑变化 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | | PKG-HLS-03 | artplayer-plugin-hls-control
整理内部职责与资源 | PKG-HLS-02, CORE-11, CORE-14 | 映射计算与 selector 更新/删除、Hls 事件订阅分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | | PKG-HLS-04 | artplayer-plugin-hls-control
迁移自有源码和公开类型 | PKG-HLS-03, ENG-04, ENG-06, CORE-07 | HLS 能力适配类型、回调上下文和旧 getName 参数 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | @@ -465,3 +465,4 @@ - PKG-CHAPTER-02: [记录](changes/2026-09-10-PKG-CHAPTER-02-tests.md) [记录](baselines/chapter-validation.json) - PKG-CHAPTER-03: [记录](changes/2026-09-10-PKG-CHAPTER-03-typescript-modules.md) [记录](baselines/chapter-migration-validation.json) - PKG-CHAPTER-04: [记录](changes/2026-09-10-PKG-CHAPTER-04-public-types.md) [记录](baselines/chapter-types-validation.json) +- PKG-HLS-01: [记录](baselines/hls-control-contract.md) [记录](baselines/hls-control-release.json) [记录](changes/2026-09-11-PKG-HLS-01-contract.md) diff --git a/refactor/progress.md b/refactor/progress.md index 333d49037..02f4e2362 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,11 @@ # 进度与证据 +## 最新完成:PKG-HLS-01 发布契约 + +HLS control 1.1.0 的六文件归档、历史源码、声明/README/manifest 与两段主逻辑对照通过。新增独立冻结记录及只读重验工具;保留 BASE-01。空轨道旧菜单、过期回调、Auto 状态、getName 类型及示例清理已映射到后续任务,没有把静态观察写成 SDK 或浏览器通过。 + +见 [契约](baselines/hls-control-contract.md) 与 [交付记录](changes/2026-09-11-PKG-HLS-01-contract.md)。62 done、153 todo;本任务独立本地 commit,核实后进入 PKG-HLS-02 的旧版行为测试。完整目标与性能/发布剩余事项不变。 + ## 最新完成:CORE-22 核心结构与兼容自动化验收 核心阶段完成,完整目标继续覆盖全部 22 包。本任务在设置导航优化之外,按实际 CPU 热点移除了原生 ResizeObserver 环境中构造时的额外控件布局读取;首次布局结果、fallback、窄屏字幕与销毁都有三引擎回归。三个生产 TS 模块、生成产物、诊断脚本及包内架构说明同步交付。 diff --git a/refactor/scripts/hls-contract.mjs b/refactor/scripts/hls-contract.mjs new file mode 100644 index 000000000..5e5d7a9b8 --- /dev/null +++ b/refactor/scripts/hls-contract.mjs @@ -0,0 +1,69 @@ +import assert from 'node:assert/strict' +import { execFileSync } from 'node:child_process' +import fs from 'node:fs' +import path from 'node:path' +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import { transform } from 'esbuild' +import ts from 'typescript' +import { archiveFiles, ensureArchive, hash, readMember, refactorDir } from './releases.mjs' + +const root = path.resolve(refactorDir, '..') +export const normalizeLF = value => value.toString().replace(/\r\n/g, '\n') + +export async function functionHash(code) { + const source = ts.createSourceFile('hls.js', code, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS) + assert.equal(source.parseDiagnostics.length, 0, 'Invalid HLS source') + const names = ['uniqBy', 'artplayerPluginHlsControl'] + const functions = names.map((name) => { + const matches = source.statements.filter(item => ts.isFunctionDeclaration(item) && item.name?.text === name) + assert.equal(matches.length, 1, `Expected one function: ${name}`) + return matches[0].getText(source).replace(/^export\s+default\s+/, '') + }) + const normalized = await transform(functions.join('\n'), { + loader: 'js', + target: 'es2020', + minifySyntax: true, + minifyWhitespace: true, + }) + return hash(normalized.code) +} + +export async function verifyHlsContract() { + const baseline = JSON.parse(fs.readFileSync(path.join(refactorDir, 'baselines/hls-control-release.json'), 'utf8')) + const { release } = baseline + const archive = await ensureArchive(release) + assert.deepEqual(archiveFiles(archive), Object.keys(release.files).sort()) + for (const [member, expected] of Object.entries(release.files)) { + assert.equal(hash(readMember(archive, member)), expected, `Changed release member: ${member}`) + } + const manifest = JSON.parse(readMember(archive, 'package/package.json')) + assert.deepEqual(manifest, release.manifest) + for (const entry of [manifest.main, manifest.module, manifest.types, manifest.legacy]) { + assert(Object.hasOwn(release.files, `package/${entry.replace(/^\.\//, '')}`)) + } + assert(/^[a-f\d]{40}$/.test(baseline.sourceCommit)) + const historical = new Map() + for (const [file, expected] of Object.entries(baseline.source)) { + const content = normalizeLF(execFileSync('git', ['show', `${baseline.sourceCommit}:${file}`], { cwd: root })) + assert.equal(hash(content), expected, `Changed historical source: ${file}`) + historical.set(file, content) + } + for (const comparison of baseline.comparisons) { + const published = hash(normalizeLF(readMember(archive, `package/${comparison.file}`))) + const source = hash(historical.get(`packages/${release.name}/${comparison.file}`)) + assert.equal(published, comparison.publishedLF) + assert.equal(source, comparison.workspaceLF) + assert.equal(published === source, comparison.equal) + } + const sourceHash = await functionHash(historical.get(`packages/${release.name}/src/index.js`)) + const publishedHash = await functionHash(readMember(archive, `package/${manifest.module.replace(/^\.\//, '')}`).toString()) + assert.equal(sourceHash, baseline.functionComparison.sha256) + assert.equal(publishedHash, sourceHash) + console.log(`Verified ${release.name}@${release.version}: archive, ${Object.keys(release.files).length} members, historical sources, metadata and two normalized functions`) + return { baseline, archive } +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + await verifyHlsContract() +} diff --git a/refactor/tasks.json b/refactor/tasks.json index c67b96589..1b22987bc 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -1782,11 +1782,15 @@ "dependsOn": [ "BASE-05" ], - "status": "todo", + "status": "done", "risk": "H", "deliverable": "quality/audio 配置、getName、update、控件名及 Hls 实例绑定", "acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结", - "evidence": [] + "evidence": [ + "baselines/hls-control-contract.md", + "baselines/hls-control-release.json", + "changes/2026-09-11-PKG-HLS-01-contract.md" + ] }, { "id": "PKG-HLS-02",