@@ -145,67 +145,83 @@ export const SHADOW_RESIDUAL: readonly { file: string; kind: ShadowResidualKind;
145145 * · 同一次提交必须手工抬高 `FROZEN_SURFACE_TAG_TOTAL` **并**同步 `SURFACE_TAG_ANCHOR.entries`
146146 * (只许抬高到「Σ 登记值」;凭空抬高总数而不登记 ⇒ 红)。
147147 * ③ **两条共同**:未登记文件的命中仍然 = 0;登记的文件必须**真实存在**(在扫描面内)且
148- * **此刻仍命中 == count**(防僵尸登记);`file` 唯一;键按字典序(与 `FROZEN_*_BY_FILE` 同范式);
148+ * **此刻仍命中 == count**(防僵尸登记);**`(file, tier)` 唯一**(同一文件**可以两行** —— `legacy`
149+ * 一行 + `new` 一行,这正是 T19 开的合法路径);键按字典序(与 `FROZEN_*_BY_FILE` 同范式);
149150 * `reason` 必须写明**哪个视图 / 为什么必须用 `<Surface>`**(≥ 12 字,照 `SHADOW_RESIDUAL` 范式)。
151+ * ④ **T19:同一文件两行时的算术**(键 `file` → `(file, tier)` 的**唯一**目的):
152+ * · legacy 档:`实测 − 该文件 new 档登记值之和` = 残存的 legacy 面 ⇒ 仍须 `≤` 登记值(且 ≠ 0);
153+ * · new 档:`实测 − 该文件 legacy 档登记值之和` 必须**恰等于** new 档登记值之和(不是 ≤);
154+ * · 全局「Σ 登记值 == 总数 == Σ 实测」+ 逐文件「登记值之和 ≥ 实测」⇒ 两侧恒等式同时成立。
155+ * ⇒ **legacy 文件内新增一处 `<Surface>`** 的合法路径 = 加一行 `tier: "new"`(值 = 新增处数)
156+ * + 抬 `FROZEN_SURFACE_TAG_TOTAL` + 同步 `SURFACE_TAG_ANCHOR.entries`;🔴 **不许**抬 legacy 面
157+ * (那条路被 §C9.5 / §C35.2 明文封死,抬了也过不了 `SURFACE_TAG_FROZEN_LEGACY_COUNT` 之和锁)。
150158 *
151159 * ★ 为什么本表住这里而不是 `surfaceBaseline.ts`:基线件已贴近 300 行硬限,而「登记为什么」本来就是
152160 * 本件的归处(`BORDER_RESIDUAL` / `RADIUS_RESIDUAL` / `SHADOW_RESIDUAL` 同住);冻结的**数**仍在
153161 * 基线件(`FROZEN_SURFACE_TAG_TOTAL` / `SURFACE_TAG_FROZEN_LEGACY_COUNT` / `SURFACE_TAG_ANCHOR`)。
154162 *
155- * ★ 新登记的写法(照抄本行并同步总数与锚;**顺序按字典序插入**):
156- * `{ file: "views/<新视图>.tsx", count: N, reason: "<哪个视图>:<为什么必须用 Surface(而不是 token 变量)>" }`
163+ * ★ 新登记的写法(照抄本行并同步总数与锚;**顺序按 `(file, tier)` 字典序插入** —— 同一文件时
164+ * `legacy` 行在前):
165+ * `{ file: "views/<新视图>.tsx", count: N, tier: "new", reason: "<哪个视图>:<为什么必须用 Surface>" }`
157166 *
158167 * 副作用:无(纯数据)。边界:`file` 是**相对 `app/src` 的正斜杠路径**,与棘轮扫描面的键同一形态。
159168 */
169+ /** 登记行的**档位** —— T19 起它是键的第二元(`键 = \`${file}|${tier}\``) */
170+ export type SurfaceTagTier = "legacy" | "new" ;
171+
160172export interface SurfaceTagRegistryEntry {
161173 readonly file : string ;
162- /** 该文件允许的 `<Surface>` 开标签处数:legacy 行 = 上限(只许降)· 新登记行 = **恰等于**实测 */
174+ /** 该文件允许的 `<Surface>` 开标签处数:` legacy` 档 = 上限(只许降)· `new` 档 = **恰等于**实测 */
163175 readonly count : number ;
164176 /**
165- * `true` = T17-B 迁移快照的既有文件(登记值 = `≤` 上限、受「legacy 之和 == 冻结迁移面」锁);
166- * 省略 = **本批新登记**(登记值必须**恰等于**实测,且同批须抬高总数与锚)—— 这条区分就是二档判据的开关。
177+ * 档位 = 键的第二元(**显式必填**:可选字段的「漏写 = new 档」在两种语义间摇摆)。
178+ * `"legacy"` = T17-B 迁移快照的既有文件(登记值 = `≤` 上限、受「legacy 档之和 == 冻结迁移面」锁);
179+ * `"new"` = 批 5 起**新登记**(登记值必须**恰等于**实测,且同批须抬高总数与锚)—— 这条区分就是二档判据的开关。
167180 */
168- readonly legacy ?: true ;
181+ readonly tier : SurfaceTagTier ;
169182 /** 哪个视图 / 为什么需要 `<Surface>`(判据要求 ≥ 12 字,不许空理由) */
170183 readonly reason : string ;
171184}
172185
173186/**
174187 * T17-B 迁移快照的 9 个文件(`count` = 当时**实测值**;其和 = 14 = `SURFACE_TAG_FROZEN_LEGACY_COUNT`
175- * = `FROZEN_SURFACE_TAG_TOTAL`)。这 9 行是**冻结面**:只许在真迁走时手工收紧,**不许**为容纳新调用点而抬高。
176- * (`legacy: true` 是那 9 行的**唯一**标记 —— 判据据此把它们与新登记行分开;总数由常数另行核验。)
188+ * = 该档在 `FROZEN_SURFACE_TAG_TOTAL` 里的份额)。这 9 行是**冻结面**:只许在真迁走时手工收紧,**不许**
189+ * 为容纳新调用点而抬高。(`tier: "legacy"` 是那 9 行的**唯一**标记 —— 判据据此把它们与 new 档分开;
190+ * 总数由常数另行核验。)
191+ *
192+ * ★ T19:键 = `(file, tier)` ⇒ 同一文件可**两行并存**(`legacy` + `new`);`legacy` 行仍只许降。
177193 */
178194export const SURFACE_TAG_REGISTRY : readonly SurfaceTagRegistryEntry [ ] = [
179195 // ⚠️ 全表按键**字典序**(判据 ⑪ 牙 5a)⇒ 新行插在字典序位置,不是追加在尾部。
180- // `legacy: true ` = T17-B 迁移快照的 9 行(`≤` 上限、只许降、其和锁在 `SURFACE_TAG_FROZEN_LEGACY_COUNT`);
181- // 不带 `legacy ` = 批 5/7 的新登记行(`count` **恰等于实测**)。新增 = 加行 + 抬总数 + 同步锚(三处同批)。
182- { file : "components/AiProviderSettings.tsx" , count : 1 , reason : "Provider 卡片容器(整圈边框 + 圆角 + 无底色):批 7 T7 迁入,走 `level=\"none\"` 只出边框不出底" } ,
183- { file : "components/AiServicePanel.tsx" , count : 1 , reason : "调用记录滚动容器(无底色 + 整圈边框):批 7 T7 迁入 `level=\"none\"`,滚动口是布局口、仍走 `style`" } ,
184- { file : "components/AiTaskPanel.tsx" , count : 1 , reason : "任务记录滚动容器(无底色 + 整圈边框):批 7 T7 迁入 `level=\"none\"`,形态同 `AiServicePanel`" } ,
185- { file : "components/ChatMessageList.tsx" , count : 2 , legacy : true , reason : "T17-B 第 2 批迁移:聊天消息流的两处卡片容器(`Surface` 出面 + 调用点只留排布)⇒ 属迁移面,非本批新增" } ,
186- { file : "components/ClassroomCapturePanel.tsx" , count : 1 , reason : "实时捕获卡片容器(原 `const panel` 共享样式):批 7 T7 把常量换成原语 `level=\"none\" radius=\"panel\" padded`" } ,
187- { file : "components/ClassroomRightPane.tsx" , count : 1 , reason : "右栏「当前配置」卡(原 `const panel` + spread):批 7 T7 换成原语,布局口(marginTop/字色)留在 `style`" } ,
188- { file : "components/EnrichPanel.tsx" , count : 2 , legacy : true , reason : "T17-B 第 2 批迁移:增强面板的两处卡片容器(整圈 `1px solid #e5e7eb` + 底色 + 非交互)⇒ 属迁移面" } ,
189- { file : "components/FeedFragmentList.tsx" , count : 1 , legacy : true , reason : "T17-B 第 2 批迁移:信息流片段的卡片容器 ⇒ 属迁移面" } ,
190- { file : "components/GoalAiSection.tsx" , count : 1 , legacy : true , reason : "T17-B 第 2 批迁移:目标页 AI 区块的卡片容器 ⇒ 属迁移面" } ,
191- { file : "components/KnowledgeSampleView.tsx" , count : 1 , legacy : true , reason : "T17-B 第 2 批迁移:知识样例视图的阅读面 ⇒ 属迁移面" } ,
192- { file : "components/LiveImageStrip.tsx" , count : 1 , legacy : true , reason : "T17-B 第 2 批迁移:实时图像条的容器面 ⇒ 属迁移面" } ,
193- { file : "components/MaterialInputPanel.tsx" , count : 1 , reason : "学习素材卡容器(原 `const panel` 共享样式):批 7 T7 换成原语 `level=\"none\" radius=\"panel\" padded`" } ,
194- { file : "components/NotePreviewView.tsx" , count : 2 , reason : "AI 精修版 / 规则版预览的 markdown 阅读面(两处 `dangerouslySetInnerHTML`):批 7 T7 用受控槽 `html` 迁入" } ,
195- { file : "components/NoteTagsEditor.tsx" , count : 1 , reason : "标签编辑浮层(批 7 T18:`level=\"raised\"` 锚定面板,底/边/圆角/阴影四件都得走原语——该文件为新建件,无任何冻结键可承接字面量)" } ,
196- { file : "components/PhotoCapturePanel.tsx" , count : 1 , reason : "图文采集卡容器(原 `const panel` 共享样式):批 7 T7 换成原语 `level=\"none\" radius=\"panel\" padded`" } ,
197- { file : "components/PracticeQuestionsOverlays.tsx" , count : 2 , reason : "练习条目行容器(整圈边框 + 无底色,两处):批 7 T7 迁入 `level=\"none\"`,行内排布留在 `style`" } ,
198- { file : "components/ProfileDetector.tsx" , count : 1 , reason : "视频档案卡容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\" radius=\"panel\" padded`" } ,
199- { file : "components/ReadyCheckCard.tsx" , count : 1 , reason : "就绪检查卡容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\" radius=\"panel\" padded`" } ,
200- { file : "components/RefineLaunchDialog.tsx" , count : 1 , reason : "画面理解开关行容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\"`,flex 排布留在 `style`" } ,
201- { file : "components/RefineStrategyPicker.tsx" , count : 1 , reason : "「高级微调」旋钮层容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\"`" } ,
202- { file : "components/RefineWorkbench.tsx" , count : 1 , reason : "差异单列视图的 diff 阅读面(`dangerouslySetInnerHTML`):批 7 T7 用受控槽 `html` 迁入" } ,
203- { file : "components/SessionSearchBar.tsx" , count : 1 , reason : "标题/内容/画面三档分组按钮的容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\"`" } ,
204- { file : "components/TaskConversationView.tsx" , count : 3 , legacy : true , reason : "T17-B 第 2 批迁移:任务对话视图的 3 处面(**同时是登记制的锚文件**,值 3 不许动)⇒ 属迁移面" } ,
205- { file : "components/VersionPanel.tsx" , count : 2 , legacy : true , reason : "T17-B 第 2 批迁移:版本面板的两处卡片容器 ⇒ 属迁移面" } ,
206- { file : "components/VideoImportPanel.tsx" , count : 1 , reason : "视频导入卡容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\" radius=\"panel\" padded`" } ,
207- { file : "components/WeekContractCard.tsx" , count : 1 , legacy : true , reason : "T17-B 第 2 批迁移:周契约卡片的面 ⇒ 属迁移面" } ,
208- { file : "components/action-center/ActionCenterPanel.tsx" , count : 3 , reason : "待提炼行 / SOP 模板区 / 模板行三个容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\"`" } ,
209- { file : "components/session-detail/SessionScreenCards.tsx" , count : 1 , reason : "OCR 屏卡容器(带锚点 `id` + 近白底):批 7 T7 用受控槽 `domId` 迁入,`level=\"canvas\"`" } ,
210- { file : "pages/SettingsPage.tsx" , count : 10 , reason : "设置页 10 个面板容器(原 `const panel` + spread):批 7 T7 换成原语 `level=\"none\" radius=\"panel\" padded`" } ,
196+ // `tier: "legacy" ` = T17-B 迁移快照的 9 行(`≤` 上限、只许降、其和锁在 `SURFACE_TAG_FROZEN_LEGACY_COUNT`);
197+ // `tier: "new" ` = 批 5/7 的新登记行(`count` **恰等于实测**)。新增 = 加行 + 抬总数 + 同步锚(三处同批)。
198+ { file : "components/AiProviderSettings.tsx" , count : 1 , tier : "new" , reason : "Provider 卡片容器(整圈边框 + 圆角 + 无底色):批 7 T7 迁入,走 `level=\"none\"` 只出边框不出底" } ,
199+ { file : "components/AiServicePanel.tsx" , count : 1 , tier : "new" , reason : "调用记录滚动容器(无底色 + 整圈边框):批 7 T7 迁入 `level=\"none\"`,滚动口是布局口、仍走 `style`" } ,
200+ { file : "components/AiTaskPanel.tsx" , count : 1 , tier : "new" , reason : "任务记录滚动容器(无底色 + 整圈边框):批 7 T7 迁入 `level=\"none\"`,形态同 `AiServicePanel`" } ,
201+ { file : "components/ChatMessageList.tsx" , count : 2 , tier : "legacy" , reason : "T17-B 第 2 批迁移:聊天消息流的两处卡片容器(`Surface` 出面 + 调用点只留排布)⇒ 属迁移面,非本批新增" } ,
202+ { file : "components/ClassroomCapturePanel.tsx" , count : 1 , tier : "new" , reason : "实时捕获卡片容器(原 `const panel` 共享样式):批 7 T7 把常量换成原语 `level=\"none\" radius=\"panel\" padded`" } ,
203+ { file : "components/ClassroomRightPane.tsx" , count : 1 , tier : "new" , reason : "右栏「当前配置」卡(原 `const panel` + spread):批 7 T7 换成原语,布局口(marginTop/字色)留在 `style`" } ,
204+ { file : "components/EnrichPanel.tsx" , count : 2 , tier : "legacy" , reason : "T17-B 第 2 批迁移:增强面板的两处卡片容器(整圈 `1px solid #e5e7eb` + 底色 + 非交互)⇒ 属迁移面" } ,
205+ { file : "components/FeedFragmentList.tsx" , count : 1 , tier : "legacy" , reason : "T17-B 第 2 批迁移:信息流片段的卡片容器 ⇒ 属迁移面" } ,
206+ { file : "components/GoalAiSection.tsx" , count : 1 , tier : "legacy" , reason : "T17-B 第 2 批迁移:目标页 AI 区块的卡片容器 ⇒ 属迁移面" } ,
207+ { file : "components/KnowledgeSampleView.tsx" , count : 1 , tier : "legacy" , reason : "T17-B 第 2 批迁移:知识样例视图的阅读面 ⇒ 属迁移面" } ,
208+ { file : "components/LiveImageStrip.tsx" , count : 1 , tier : "legacy" , reason : "T17-B 第 2 批迁移:实时图像条的容器面 ⇒ 属迁移面" } ,
209+ { file : "components/MaterialInputPanel.tsx" , count : 1 , tier : "new" , reason : "学习素材卡容器(原 `const panel` 共享样式):批 7 T7 换成原语 `level=\"none\" radius=\"panel\" padded`" } ,
210+ { file : "components/NotePreviewView.tsx" , count : 2 , tier : "new" , reason : "AI 精修版 / 规则版预览的 markdown 阅读面(两处 `dangerouslySetInnerHTML`):批 7 T7 用受控槽 `html` 迁入" } ,
211+ { file : "components/NoteTagsEditor.tsx" , count : 1 , tier : "new" , reason : "标签编辑浮层(批 7 T18:`level=\"raised\"` 锚定面板,底/边/圆角/阴影四件都得走原语——该文件为新建件,无任何冻结键可承接字面量)" } ,
212+ { file : "components/PhotoCapturePanel.tsx" , count : 1 , tier : "new" , reason : "图文采集卡容器(原 `const panel` 共享样式):批 7 T7 换成原语 `level=\"none\" radius=\"panel\" padded`" } ,
213+ { file : "components/PracticeQuestionsOverlays.tsx" , count : 2 , tier : "new" , reason : "练习条目行容器(整圈边框 + 无底色,两处):批 7 T7 迁入 `level=\"none\"`,行内排布留在 `style`" } ,
214+ { file : "components/ProfileDetector.tsx" , count : 1 , tier : "new" , reason : "视频档案卡容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\" radius=\"panel\" padded`" } ,
215+ { file : "components/ReadyCheckCard.tsx" , count : 1 , tier : "new" , reason : "就绪检查卡容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\" radius=\"panel\" padded`" } ,
216+ { file : "components/RefineLaunchDialog.tsx" , count : 1 , tier : "new" , reason : "画面理解开关行容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\"`,flex 排布留在 `style`" } ,
217+ { file : "components/RefineStrategyPicker.tsx" , count : 1 , tier : "new" , reason : "「高级微调」旋钮层容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\"`" } ,
218+ { file : "components/RefineWorkbench.tsx" , count : 1 , tier : "new" , reason : "差异单列视图的 diff 阅读面(`dangerouslySetInnerHTML`):批 7 T7 用受控槽 `html` 迁入" } ,
219+ { file : "components/SessionSearchBar.tsx" , count : 1 , tier : "new" , reason : "标题/内容/画面三档分组按钮的容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\"`" } ,
220+ { file : "components/TaskConversationView.tsx" , count : 3 , tier : "legacy" , reason : "T17-B 第 2 批迁移:任务对话视图的 3 处面(**同时是登记制的锚文件**,值 3 不许动)⇒ 属迁移面" } ,
221+ { file : "components/VersionPanel.tsx" , count : 2 , tier : "legacy" , reason : "T17-B 第 2 批迁移:版本面板的两处卡片容器 ⇒ 属迁移面" } ,
222+ { file : "components/VideoImportPanel.tsx" , count : 1 , tier : "new" , reason : "视频导入卡容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\" radius=\"panel\" padded`" } ,
223+ { file : "components/WeekContractCard.tsx" , count : 1 , tier : "legacy" , reason : "T17-B 第 2 批迁移:周契约卡片的面 ⇒ 属迁移面" } ,
224+ { file : "components/action-center/ActionCenterPanel.tsx" , count : 3 , tier : "new" , reason : "待提炼行 / SOP 模板区 / 模板行三个容器(整圈边框 + 无底色):批 7 T7 迁入 `level=\"none\"`" } ,
225+ { file : "components/session-detail/SessionScreenCards.tsx" , count : 1 , tier : "new" , reason : "OCR 屏卡容器(带锚点 `id` + 近白底):批 7 T7 用受控槽 `domId` 迁入,`level=\"canvas\"`" } ,
226+ { file : "pages/SettingsPage.tsx" , count : 10 , tier : "new" , reason : "设置页 10 个面板容器(原 `const panel` + spread):批 7 T7 换成原语 `level=\"none\" radius=\"panel\" padded`" } ,
211227] ;
0 commit comments