# 跨镜一致性锁

## 目录

- [为什么识别锚点还不够](#为什么识别锚点还不够)
- [什么值得上锁](#什么值得上一把锁)
- [锁面怎么写](#锁面怎么写)
- [语法](#语法)
- [谁负责把锁面带走](#谁负责把锁面带走)
- [反例](#反例)
- [校验](#校验)

## 为什么识别锚点还不够

识别锚点是写给创作者读的事实；执行端读不到它，只读得到每条提示词自己的正文。同一件毛衣第一镜
织的是蓝色、第二镜变成红色，通常不是资产写错了，而是**没有任何一条提示词把颜色带进去**：视觉
设定写了，关键帧写了一半，运动提示词以为参考帧已经交代过就把重复描述删掉了。

参考图也补不上这一层。一张角色板只能约束它自己画到的部分；正在编织、只成形一半的毛衣，被手挡住
的道具，每镜重新构图的服装细节，都落在身份参考“默认不能控制”的一侧。

一致性锁固定跨镜不变的可见事实，要求其锁面原样出现在生效范围内的提示词正文中。

## 什么值得上一把锁

三条同时成立才值得上锁：

1. 这个可见事实在本集出现于两个以上镜头，或一个镜头加一张资产板；
2. 观众能直接看出前后不一致；
3. 它不随剧情改变——会变的是状态，**状态不上锁**。

典型：服装主色与形制、道具主色与材质、发型长度、伤口位置与形状、招牌或界面的形制配色。
不典型：情绪、姿势、左右手、镜头角度、时段光线、破损进度、持有人——这些是状态或镜头瞬态，
分别归 `本集状态` 与分镜。

**`craft_default`**： 一集里的锁通常是个位数。把每条识别锚点都升级成锁，每条提示词都会被同一串
名词短语撑满，反而挤掉本镜真正要执行的动作。

## 锁面怎么写

`锁面` 是**要被逐字带进提示词正文的最小可辨识词组**：

- 锁面必须**逐字出现在它管到的每一份可复制正文里**。校验器会在三处查同一个字符串：
  图片提示词正文、冻结关键帧提示词、视频提示词正文。
- 图片与冻结关键帧使用 `format/prompt_language`，视频可能使用另选的 `video_prompt_language`。
  语言不同时，优先使用确实适合各份正文的共同色值、型号或专名。
  当前 `镜头：` 同时约束本镜首帧与视频正文，不能靠拆成两把锁分别约束两种语言。
  没有合适共同词组时，在视觉设定中保留事实并报告此限制，暂不声明这把逐字锁；
  不缩小事实实际出现的镜头范围来绕过检查，也不自行改变用户选择的正文语言。

- 只保留最小可辨识名词短语，通常是「颜色 + 材质/形制 + 物体」，例如
  `pale blue chunky knit wool sweater`；
- 不含句号、动作、状态、数量、镜头信息和剧情；
- 不写会随镜头变化的词（`in her hands`、`half-finished`、`on the sofa`）；
- 一个实体一把锁；同一实体的两种造型是两把锁，各写各的生效镜头。

比较时忽略大小写，换行按空格处理（可复制正文本来就渲染成一段，硬折行不影响匹配），其余字符
逐字比较。提示词可以在锁面前后接语法（`she keeps knitting the pale blue chunky knit wool
sweater`），但不能改写锁面内部——少一个 `stand-collar`、多一个逗号都算漂移。

以下两类字符串命中不能证明锁面被正面描述：

- **粘在词上的匹配不算**。锁面首尾是字母数字时，紧挨着的字母数字或连字符会让它落空：
  `chipped white enamel mug` 不被 `unchipped white enamel mug` 满足，
  `pale blue knit` 不被 `pale blue knitwear-print fleece` 满足。锁面要能作为一个完整的词组读出来。
- **负面提示词里的匹配不算**。写在 `no`/`not`/`without`/`avoid` 或 `不要`/`不能`/`没有`/`避免`
  之后的锁面说的是「不要出现它」，正好与锁的目的相反；`..., no pale blue chunky knit wool
  sweater` 不能作为锁面在场的证据。锁面必须出现在描述画面内容的正文里。
  「粘在词上」只对 ASCII 词生效——中文本来不分词，`织着浅蓝色粗棒针毛线` 正常命中。

## 语法

写在 `视觉设定.md` 对应资产条目下，与识别锚点并列：

```markdown
## 道具 · 织了一半的毛衣

- 识别锚点：浅蓝色粗棒针手织毛线，竹制棒针两根，衣身只织到胸口。
- 本集状态：SC002 起衣身加长约一掌；颜色与针法不变。
- 连续性锁：LOCK-KNIT《织了一半的毛衣》（镜头：全集；图片提示词项：IMG-PROP-KNIT）· 锁面：pale blue chunky knit wool sweater
```

- 列表记号写 `-`、`*` 还是 `+`，缩进几格，都不影响识别；一条看起来像锁却写不完整的行会被
  报成语法错误，不会被悄悄跳过——锁不能变成空转；
- `LOCK-...`：本集唯一稳定 ID，与 `IMG-...`、`REF-...`、`SHOT-...` 互不混用；
- `《中文名》`：给创作者读的名称，必须含中文；
- `镜头：`：`入画`、`全集`，或 `、` 分隔的 `SHOT-...` 列表；三者不能混写。`入画` 由检查器展开成「视觉依据」
  列出本条目的所有镜头，所以锁要写在它所属的人物、造型、地点或道具条目下面；
- `图片提示词项：`：可选，`、` 分隔的 `IMG-...` 列表，整段省略即表示不约束图片提示词；
- `锁面：`：被逐字带走的那段字，写在行尾。

## 谁负责把锁面带走

| 文档 | 义务 |
|---|---|
| `图片提示词.md` | 被点名的 `IMG-...` 可复制正文含锁面，让参考图本身就是对的 |
| `分镜.md` | 生效镜头的冻结关键帧提示词含锁面 |
| `视频提示词.md` | 对应 `MOTION-...` 可复制正文含锁面 |

**`structural_invariant` CON-07**： 锁面在生效范围内不得以“参考帧已经交代过”为由删除。图生视频
可以删去重复的静态描述，连续性锁的锁面仍须保留。

状态变化不进锁面：毛衣越织越长写在 `本集状态`，颜色和针法写在锁面。两者同时存在时，提示词自己
写长度，锁面负责颜色和针法。

## 反例

- `锁面：蓝色毛衣`——提示词正文是英文时永远匹配不上，且“蓝色”分不出浅蓝和藏青；
- `锁面：a pale blue sweater that she has been knitting since the first scene`——含剧情和时态，
  下一镜必须改写它，锁当场失效；
- `锁面：high quality, detailed`——不是可辨识事实，锁住了也证明不了一致；
- 只把锁的 `镜头` 范围写到「文字已经对的那几镜」——范围要按这个事实**实际出现在哪几镜**来写，
  按已经写对的地方来写，等于把校验器指向没有风险的位置；
- 把 `镜头：全集` 用在只出现两镜的道具上——其余镜头会被迫写入与本镜无关的名词。用 `入画`。
- 把服装锁写在人物条目下并用 `入画`——手部特写、眼部大特写也列这个人物，会被迫写进看不见的衣服。
  服装锁写在 `造型` 条目下，分镜只在衣服入画时列这个造型。

## 校验

```bash
python3 <core 技能目录>/scripts/creator_markdown_check.py 剧集/<EP> --project-root . --partial
```

资产阶段只有剧本、视觉设定和图片提示词时，`--partial` 照样核对锁的语法和被点名的 `IMG-...` 正文；
镜头范围在分镜写完后自动生效，不需要回来改锁。

它只机械核对语法、范围可解析，以及锁面是否真的出现在被点名的正文里。该不该上这把锁、锁面写得
准不准，仍由创作者和审查判断。
