diff --git a/content/chapters/chapter2.json b/content/chapters/chapter2.json index e7a82a5..8cdd7ca 100644 --- a/content/chapters/chapter2.json +++ b/content/chapters/chapter2.json @@ -16,7 +16,7 @@ "id": "c2-d1v", "type": "dialogue", "speaker": "旁白", - "text": "【若 c1_06_landing = b_precise】黄昏,苍梧城内西市。西市正收摊,灯笼却没亮——满城无灯。落点舱的余震还在耳膜里,你已经站在了一千年前的苍梧城里。没有人看见你出现,但你觉得整座城都看见了:家家户户门窗紧闭,街上的人走路都贴着墙根。一个卖炊饼的老汉收摊时看了你一眼,那一眼不是好奇,是数你。天上最后一线光里,你忽然明白资料里那句话是什么意思:「苍梧最后一个月,夜不举火。」人在怕。只是不知道在怕什么。", + "text": "【若 c1_06_landing = b_precise】黄昏,苍梧城内西市。西市正收摊,灯笼却没亮——满城无灯。落点舱的余震还在耳膜里,你已经站在了一千年前的苍梧城里。没有人看见你出现,但你觉得整座城都看见了:家家户户门窗紧闭,街上的人走路都贴着墙根。一个卖炊饼的老汉收摊时看了你们一眼——不是看生人的好奇:他的目光挨个儿从你们五张脸上过了一遍,像点货,点完便低头继续收他的摊。夜禁的城里,生面孔是稀罕物,多一张,街坊都要记挂几天。天上最后一线光里,你忽然明白资料里那句话是什么意思:「苍梧最后一个月,夜不举火。」人在怕。只是不知道在怕什么。", "sprite": "scene", "next": "c2-d1a" }, @@ -212,7 +212,7 @@ { "signature": "遗憾但坦然", "variantId": "intel_mid", - "label": "【同路】界碑前他把方位时辰又对了一遍,才肯动身。你们自己走进月下的封土群,他跟在后头一路没再多话,找到那块「会唱歌的石头」时才嗯了一声。到暗门口,他多说一句:「放得下的,才叫过去。」门缝开了才走。基调:得体的距离。", + "label": "【同路】界碑前他把方位时辰又对了一遍,才肯动身。你们自己走进月下的封土群,他跟在后头一路没再多话。路过那块「会唱歌的石头」时,夜风正巧从石窍里过,石头低低地呜了一声,像谁在很远的地方应了个声——他嗯了一下,算是跟它打了招呼。到暗门口,他多说一句:「放得下的,才叫过去。」门缝开了才走。基调:得体的距离。", "tint": "#a0964b" }, { diff --git a/content/chapters/chapter3.json b/content/chapters/chapter3.json index 92141e2..52d17f6 100644 --- a/content/chapters/chapter3.json +++ b/content/chapters/chapter3.json @@ -8,7 +8,7 @@ "id": "c3-d1", "type": "dialogue", "speaker": "旁白", - "text": "暗门后的台阶比想象中长。走到一半你就明白了:这不是墓。墓是让人安息的地方,这里是让人等待的地方。祭祀坑一层压着一层,器物成组地朝着南方,像一片朝着太阳倒伏的麦田。考古报告里那个你标注过无数次的词,此刻从纸上站了起来——禳。这不是下葬。这是祈福。整座宫墟,是苍梧人修给上天的、一封加急的信。", + "text": "探灯的光最后扫过暗门的门楣——上面凿着一个字,校准室里那块残碑上的同一个:「安」。碑说,它镇的方向就是安门。你们到了。暗门后的台阶比想象中长。走到一半你就明白了:这不是墓。墓是让人安息的地方,这里是让人等待的地方。祭祀坑一层压着一层,器物成组地朝着南方,像一片朝着太阳倒伏的麦田。考古报告里那个你标注过无数次的词,此刻从纸上站了起来——禳。这不是下葬。这是祈福。整座宫墟,是苍梧人修给上天的、一封加急的信。", "sprite": "scene", "next": "c3-d1a" }, diff --git a/docs/script/act1.md b/docs/script/act1.md index 9c3bd3f..575b548 100644 --- a/docs/script/act1.md +++ b/docs/script/act1.md @@ -530,7 +530,9 @@ score。对 `confidence < 0.6` 的维度,在第 2 章插入对应支线 > > 没有人看见你出现。但你觉得整座城都看见了——家家户户门窗 > 紧闭,街上的人走路都贴着墙根。一个卖炊饼的老汉收摊时看了 -> 你一眼,那一眼不是好奇,是**数你**。 +> 你们一眼——不是看生人的好奇:他的目光挨个儿从你们五张脸上 +> 过了一遍,像点货,点完便低头继续收他的摊。夜禁的城里, +> 生面孔是稀罕物,多一张,街坊都要记挂几天。 > > 天上最后一线光里,你忽然明白资料里那句话是什么意思: > 「苍梧最后一个月,夜不举火。」人在怕。只是不知道在怕什么。 @@ -539,7 +541,9 @@ score。对 `confidence < 0.6` 的维度,在第 2 章插入对应支线 > 沈铎分派:明日采集开始。 【工程】两段变体文本等长等信息量(A 给城外情报线,B 给城内氛围 -素材),汇合后主线完全一致。变体 B 的「数你」细节为 §3-7 钩子埋线。 +素材),汇合后主线完全一致。变体 B 的老汉细节在本段内自释 +(夜禁城的生面孔焦虑),不向后续章节悬置;「被注视」主题由 +§3-7 通话正面承担,跨幕伏笔一律登记于母本 §9。 --- @@ -719,7 +723,7 @@ score。对 `confidence < 0.6` 的维度,在第 2 章插入对应支线 | 情绪签名 | 演出档位 | 夜游场景基调稿 | |---|---|---| | 自责(悔指向自己) | **絮说**:一路举着火把走在前面,话不断 | 月色下的陵区,石像生的影子很长。老人举火把走在前面,脚步轻得不像老人——"陵里的路,闭眼走比睁眼走直"。行至暗门,他忽然说起自己年轻时也悔过一件事,说了半句,摆摆手不说了。摸一遍门石,等门缝开了才走。基调:**被信任的厚重** | -| 遗憾但坦然 | **同路**:话在界碑前说完,路上安静 | 界碑前他把方位时辰又对了一遍,才肯动身。你们自己走进月下的封土群,他跟在后头一路没再多话,找到那块"会唱歌的石头"时才嗯了一声。到暗门口,他多说一句:"放得下的,才叫过去。"门缝开了才走。基调:**得体的距离** | +| 遗憾但坦然 | **同路**:话在界碑前说完,路上安静 | 界碑前他把方位时辰又对了一遍,才肯动身。你们自己走进月下的封土群,他跟在后头一路没再多话。路过那块"会唱歌的石头"时,夜风正巧从石窍里过,石头低低地呜了一声,像谁在很远的地方应了个声——他嗯了一下,算是跟它打了招呼。到暗门口,他多说一句:"放得下的,才叫过去。"门缝开了才走。基调:**得体的距离** | | 愤怒指向他人 | **缄默**:方位时辰一句不落指给你,然后沉默地走在队尾 | 老人听完,编草绳的手停了很久。动身时该指的路、该说的时辰,一句没少——说完就闭了嘴,走在队尾,没再多看你一眼。可你们走出十几步,他在身后忽然开口:"火气这东西,老头子也有过一回。"没头没尾,再没下文。门缝开了,他转身就走。基调:**话到,情未到**——可那一句话,他自己也未必舍得讲给旁人 | | 沉默 | **草绳**:一下午并肩编草绳,黄昏同样起身送到门口 | 一下午你们并肩搓绳,他絮絮地说陵里的事,你默默地听。日头偏西,他拍拍手上的草屑起身,一样把你们送到暗门口。等门缝开了,他说:"不说的人,心里的事最重。重的别久揣。"基调:**笨拙的善意** | @@ -1127,6 +1131,9 @@ score。对 `confidence < 0.6` 的维度,在第 2 章插入对应支线 【正文·旁白】 +> 探灯的光最后扫过暗门的门楣——上面凿着一个字,校准室里那块 +> 残碑上的同一个:**安**。碑说,它镇的方向就是安门。你们到了。 +> > 暗门后的台阶比想象中长。走到一半你就明白了: > 这不是墓。墓是让人安息的地方,**这里是让人等待的地方**。 > @@ -1810,6 +1817,10 @@ C-2049 的燃料质量比预估高,是的,**那扇门开得很顺**。 - 叙述纪律:旁白只写可见动作与台词,不替玩家或 NPC 的心理下结论; C3-03 伤员获同等救护,差异落在安全区域的记录任务与遗存损失, NPC 不做"选得对/处置正确"式裁判(C3-03-B/C 台词已清除)。 +- 伏笔纪律:跨幕悬念一律登记于母本 §9 伏笔登记表(写明已交代/ + 待回收/建议章节);段内承诺必须在 Act 1 内兑现——C1-05"安"字 + 已于 §3-1 暗门门楣回收,"会唱歌的石头"已在 C2-02 同路档内 + 出声,§2-1 老汉细节已改为段内自释(2026-10-04)。 - 支线铁律:所有分支差异收敛于变量与文本换色,主线事件序列 对所有玩家一致(三通道原则);自适应支线仅留挂点(§2-4、§3-2 前), 支线剧本另册;支线须遵守 `wenjian_health` 贯穿约束(§2-4 末, diff --git a/docs/script/coherence-literary-review-2026-10-04.html b/docs/script/coherence-literary-review-2026-10-04.html new file mode 100644 index 0000000..4d87267 --- /dev/null +++ b/docs/script/coherence-literary-review-2026-10-04.html @@ -0,0 +1,121 @@ + + +
+ +评审对象:docs/script/act1.md、docs/script/adaptive-branches.md(2026-10-04 安全合规修订版),并对照已同步的章节与支线 JSON。
+评审口径:只看叙事质量——连贯性(有发必有收、人物与设定有出处、时间线单一事实源)与文学性(张力、意象、声口、沉浸感)。测量与合规口径不在此评。
+结论速览:剧本骨架是好的——大火星倒计时、空璧座、问心石三条意象主线贯穿有力,NPC 声口分明,章末钩子结构成熟。当前最主要的问题集中在两处:其一,上一轮安全化修订把三场高潮戏(C3-03 塌方、B-EMO-A 沙暴、B-EMO-B 压板)的动作全部换成"清点/坐标/记录/警戒线",并引入了没有出处的"接应人员",连贯与文学同时受损;其二,若干伏笔有发无收("数你"的老汉、"安"字碑、"会唱歌的石头"),正是"老人说要带你去看个东西、后文再无下文"这一类断裂。
穿越小队自始至终只有五个人:沈铎、阿棠、温简、老鬼、你。但 C3-03 的三条后续里六次出现"接应人员"("传给接应人员""由接应人员送回营地""接应人员护送"),B-EMO-B 里出现"受训人员""受训接应人员"。读者会立刻问:这些人是哪来的?——这是当前全剧最刺眼的一处设定破绽。
+值得注意的是,C3-03 的场景段其实已经把救护落在了正确的人身上("沈铎和受过救护训练的老鬼已在安全线内接管伤情"),后文的"接应人员"是改写时漏网的旧词,同一场景内自相矛盾。
+修改意见:全剧统一口径——队内急救员就是老鬼(可以在 §1-5 集结甲板的装备清单处补半句"老鬼清点着急救包——队里指定急救员从来是他",让这层身份有出处)。然后把 C3-03、B-EMO-B、附录 D 里所有"接应人员/受训人员"替换为"老鬼"或"沈铎与老鬼";"送回营地"改为"老鬼按外伤规程处置后,陪她随队撤回"。
+ +这是本次评审按您举的"守墓老人说带你看个东西"一类问题专项排查的结果。三处确认有发无收:
+同时核对确认已经闭环、不必动的伏笔,列出备查:谶语"不是人走了,是请走的"→§3-1"禳/祈福";温简板子配给疑云→C3-06 引导语;哨子/绳包扣→§3-7"攥出了汗";阿棠崴脚→少年赠药;空璧座→§3-7"璧的事一个字都不许提";大火星倒计时→§3-8 终幕。
+ +C3-03 现场写"阿棠小腿被擦伤",三条后续却都写"夜里疼醒三次,次日复查为小腿骨裂"。两个问题:其一,擦伤与骨裂是两种伤,现场能走动、能喊,伤情升级缺少中间描写;其二,苍梧宫墟里不存在"复查"的手段,这是现代医院词汇穿越回了古代现场。
+修改意见:统一为一条可信的伤情线——"塌落的夯土擦过小腿,当时疑为挫伤;回营后老鬼按外伤规程检查,判骨裂、上夹板"。三线共用这一句,把"复查"改为"老鬼检查后确认"。这样 P1-1 的急救员设定也顺势得到第二次使用。
+ +§2-8 结尾写"第 6 日黄昏,全队拔营……第 7 日清晨入宫墟",§3-1 场景又独立标注"【场景】第七日,宫墟"。同一信息两处维护,将来任何一侧改动都会漂移。
修改意见:绝对日历只在 §2-8(或附录 D)说一次,§3-1 场景删"第七日",改"清晨,宫墟"。另外 §3-8"那一天是九天后/回程八天后"的数字算术对玩家偏抽象,建议换成形象:"大火星再走七夜,就到正中;你们的回程,在第六夜。"——数字少一个,意象多一层。
自责档里老人"忽然说起自己年轻时也悔过一件事,说了半句,摆摆手不说了",其余三档没有这半句。单周目玩家看不到差异,但这是同一人物的心事,作为文案资产应当要么四档都有(措辞不同:同路档是沉默更久、缄默档是那句"火气这东西,老头子也有过一回"——这条已经有了)、要么注明自责档独有是设计而非遗漏。
修改意见:把"悔"的痕迹定为老人的固定底色:絮说档=半句悔;同路档=话到界碑前说完、其中夹一句"老头子也有过一回";缄默档=已有;草绳档=搓绳时"绳结打错了三次"这类动作化暗示。四档同源,深浅不同。
安全化修订正确地移除了危险动作示范,但把三场高潮戏的选项与后续几乎全部替换成了管理动作。试读 C3-03 的三个选项:
+A.留在阿棠这边。接手伤情记录和撤离联络,替她把疼痛与需求传给接应人员……+
+B.留在温简这边。在安全线内核对远距影像、方位与已抄铭文……
+C.调配两边的记录任务。让沈铎确认交接、温简退回安全线,先保全已有资料……
以及 B-EMO-A 沙暴中的选项:"先点人""先报坐标""先安顿队伍"。这是 Act 1 的情绪最高点与两处突发高压,但现在读起来像工地交接单。玩家在高潮处拿到的是职位描述,不是抉择。
+需要说明:问题不在安全边界本身——"人不进危险区、无操作示范"这条红线应当保留——而在张力被错误地从"动作"上拿走后,没有搬进"感官与人物"。紧张感完全可以由不涉及任何危险操作的笔墨承载:探灯光柱里暴涨的尘埃、鼎簋滑向缝口时那一寸一寸的慢、温简数拍子的声音、阿棠数自己呼吸的声音、你手心里汗把记录板洇出的印子。
+修改意见(原则:动词换体温,边界不越线)——把选项动词从"记录/核对/调配"换成玩家身体在场的动作:"把她的手攥住,替她把疼喊出来""替温简举稳灯,让他盯住那行字""什么也不做,就站在两边的中间,喊出每个人的名字"。这些动作同样零危险,但读者能借位置与触觉进入现场。文末第五节给出 C3-03 的整段示范改写。
+ +C3-02 出石室的馆长台词:"室内不录音、不留讲述文本、不入记忆展厅、不作画像输入;仅保留你完成、折返或离开的路径用于剧情接续。"——"画像输入""剧情接续"是工程与产品语言,从一个自称"收藏人怎么活过"的千年档案馆馆长嘴里说出来,等于穿帮。类似地,"路径""节点""触发"这类词都应避免进入台词层。
修改意见:台词只说世界观内的话:"你在门里说的每一个字,不记进任何册页,不算进任何数——门里的事,归你。"隐私承诺的精确边界(无文本、无画像输入)保留在工程注里,由实际数据行为兑现,不必让馆长替产品文档背书。
四档等价是测量上的硬要求,但文学呈现上,"送到暗门口、摸一遍门石、等门缝开了才走"在表格里逐档重复,读感是四段同构的说明文,老人的质感反而被冲淡。
修改意见:把等价的公共动作抽出为一段夜游正叙(放在即时回报之后,只写一遍:"无论你讲了什么,他都在黄昏起身,把你们送到暗门口,摸一遍门石,等门缝开了才转身回去"),四档表格只保留差异列——他一路说不说话、说哪句体己话。表格瘦身后,每档那句台词的分量会更清楚。
§2-8 用一句"例行采集"带过两整天。可全剧最好的悬念恰是"这座城在等那一天"——等待期的城市应当有涨落,两日真空让"城在等"变成了旁白的口头禅。
修改意见:在 §2-8 桥段加一个五十字级的轻意象事件:水门的商队开始收铜镜("镜子照天,收了天上就看不见了"),或夜里家家磨刀、声音像雨。一个细节即可让焦虑继续生长,顺便为 B-CON-A 的市集氛围提供换色锚点。
骨裂次日(C3-05),她"忽然大笑,笑得咳嗽",通场没有一处疼的痕迹。伤情变量记进了附录,身体却没记进文字。
修改意见:给她两处微动作——坐在物资堆上时"撑着膝盖,先把伤腿搁平了才敢坐";大笑笑到一半"吸了口冷气,把后半截笑咽回去,改成拍你的手背"。疼不必说出口,动作替她说。
§3-7 馆长那句"壁的事,一个字都不许提"是全季级钩子,但玩家对"璧"的全部认知只是"璧座是空的"。空与禁言之间的重量差,靠玩家自行脑补。
修改意见:§3-2 解题后,温简补一句低声的自问:"礼都备到这一步了……璧呢?"给钩子一个三小时前的抓点,禁言落下来时才有"啪"的一声。
旁白偶有说明文腔("接应人员在安全线内备好急救器材"是任务简报不是小说);个别残留短语与安全口径打架("三双手合力"之类应随 P1-1 一并再扫一遍)。建议做一次纯文字层的通读,凡是"主语+配置了+资源"式的句子,都改成"某人在做某个看得见的动作"。
+ +| 优先级 | 条目 | 位置 | 一句话改法 |
|---|---|---|---|
| 必改 P1 | 接应人员无出处 | C3-03/B-EMO-B/附录 D | 急救员定为老鬼(§1-5 补出处),全量替换 |
| 必改 P1 | 三处悬空伏笔 | §2-1/C1-05/C2-02 | "数你"入 §3-7 通话;门楣见"安";石头出声或删名 |
| 必改 P1 | 擦伤→骨裂因果 | C3-03 三线后续 | "疑为挫伤,老鬼查后判骨裂上夹板" |
| 必改 P1 | 高潮戏去张力 | C3-03/B-EMO-A/B | 选项动词换体温,感官承载张力(见示范) |
| 必改 P1 | 馆长术语泄漏 | C3-02 出室台词 | "不记进任何册页,不算进任何数" |
| 应改 P2 | 时间双源 | §2-8/§3-1 | 日历只留一处;§3-1 删"第七日" |
| 应改 P2 | 四档复读 | C2-02 变体表 | 公共夜游正叙抽出,表格只留差异 |
| 应改 P2 | 中段空转 | §2-8 | 加一个轻意象事件(收铜镜/磨刀声) |
| 应改 P2 | 阿棠痛感缺失 | C3-05 | 两处微动作 |
| 可改 P3 | "璧"钩子前置 | §3-2 结尾 | 温简自问一句"璧呢?" |
| 可改 P3 | 老人半句悔四档统一 | C2-02 | 四档同源、深浅不同 |
| 可改 P3 | 零星措辞 | 全剧 | 通读扫"配置资源"式句子 |
以下改写不含任何危险操作示范(无人进入危险区、无技术动作、无专业背书),仅以感官与人物动作承载张力,可直接替换现有正文与选项:
+++【旁白】话音未落,前方传来阿棠的喊声和一声闷响。甬道中段的夯土塌了一角。她连滚带爬退到安全线内,小腿的裤管渗了血,脸白得像甬道里的尘土。沈铎和老鬼已经蹲在她身边——老鬼是队里的急救员,剪开裤管的手很稳。沈铎头也不回:"这里够了。别过来。"
+甬道另一侧,你们今早清理出的工作面上,那组七鼎六簋正随着台基的颤动,一寸一寸滑向裂开的地缝。温简一个人守在安全线内,探灯举得笔直,光柱里尘埃像倒着下的雪。他不回头,声音是从牙缝里挤出来的:"最长的那件……腹铭三百字。我今晨只抄到第七行。"
+头顶,第二声闷响在逼近。尘土簌簌落在你的记录板上。你站在两条安全线中间——一边是阿棠压着嗓子的抽气声,一边是鼎足蹭过石缝的、指甲刮石般的声音。你只有一副眼睛、一双手。
+【选项】
+
+A.到阿棠那边去。蹲下来,把她的手攥住——老鬼处置伤,你替她把疼喊出来。
+B.到温简那边去。替他举稳备用灯,让那三百个字在他抖之前,多进镜头一行是一行。
+C.站在中间,喊出每个人的名字,一边一句,把两边都钉在原地。
说明:A/B/C 三个动作全部零危险(攥手、举灯、喊名字),合规审查不会受阻;但"指甲刮石般的声音""把疼喊出来""多进一行是一行"把抉择的重量放回了读者的身体里。后续演出可沿用现有三线结果,仅需把"接应人员"替换为"老鬼"(见 P1-1)。
+ +这份剧本的骨架——意象系统、声口、钩子结构——已经是成品水准。当前的问题集中而非弥散:连贯性上,一处设定破绽(接应人员)、一处伤情断链、三枚哑火的伏笔;文学性上,三场高潮戏在合规改写中失去了张力载体,外加一处术语穿帮。按第三节清单从 P1 顺次处理,预计两处半天工作量即可完成主体修复;修复时务必守住第四节列出的既有优点——那些是这出戏真正值钱的东西。
+ + + diff --git a/docs/script/苍梧疑冢-Act1-连贯性与文学性评审-2026-10-04.docx b/docs/script/苍梧疑冢-Act1-连贯性与文学性评审-2026-10-04.docx new file mode 100644 index 0000000..0695111 Binary files /dev/null and b/docs/script/苍梧疑冢-Act1-连贯性与文学性评审-2026-10-04.docx differ diff --git a/docs/story-framework.md b/docs/story-framework.md index 4dae612..f132ffb 100644 --- a/docs/story-framework.md +++ b/docs/story-framework.md @@ -143,3 +143,55 @@ score 问题。对 `confidence < 0.6` 的维度,在下一章插入对应支线 交付:第 1-3 章(本文档定义的全部选择点与讲述点)+ 画像报告 + 分享卡。 不含:匹配、聊天、Act 2/3、实时生成(全部走章节间预生成)。 + +## 9. 伏笔登记表(Act 1 已埋、后续章节回收清单) + +> 纪律(2026-10-04 立):跨幕悬念必须在本表登记,登记时写明 +> 「已交代什么/待回收什么/建议回收章节」;Act 1 文本内做出的 +> 段内承诺(如"你会再见到它")必须在 Act 1 内兑现,不得向 +> Act 2 之后直接借债——Act 2 必须过一手。新增伏笔不登记者, +> 视为写作事故。 + +### 9.1 主线悬念(Act 2 必收) + +| # | 伏笔 | 埋设点(旗标) | 已交代 | 待回收 | 建议章节 | +|---|---|---|---|---|---| +| 1 | 璧的下落 | §3-2 空璧座;§3-7"璧的事一个字不许提" | 礼备到最后一步、璧始终缺席、档案馆禁言 | 璧是什么、去了哪、为何禁言 | Act 2 中层真相(章末) | +| 2 | 档案馆隐瞒与"那一天" | §3-6/§3-7 通话;§3-8 早走一天(`flag_arch_doubt`) | 计划无恶意、问心石是放的、"来不及回头" | 那一天会发生什么;早走一天的正面答案 | Act 2 总线(持续) | +| 3 | 问心石的用途延伸 | §3-7"问心是我们放的";C-2049"燃料质量" | 石头非遗迹、采集数据外送 | 问心数据去向、"燃料"说法的含义 | Act 2(配合 #4) | +| 4 | 温简板子疑云 | C2-05 浅暴露线;C3-06-C-温简"情绪回收率" | 配给多于记录、多出一行回收率 | 双账本线的爆发与站队 | Act 2 温简线 | +| 5 | 沈铎隐瞒线 | C2-06-B 老鬼"不止我一个"(`flag_laogui_hint`);C3-04-B"这次我背"(`flag_shenduo_cover`) | 沈铎有所瞒、求情成把柄 | 他瞒的是什么、把柄如何爆 | Act 2 信任危机主线 | +| 6 | 老鬼动机与私藏线 | C2-06-C"急什么";C1-04-D(`flag_laogui_thread`);C3-04 事发后续 | 放回玉佩有隐情、被限行动 | 他的真实来路与交换条件 | Act 2 老鬼线 | +| 7 | 撤离后开局站位 | C3-06 三条 C 线(沈铎提前/阿棠结盟/温简双账) | 三种知情盟友 | 各自把 Act 2 开场带向何处 | Act 2 第 4 章开场 | + +### 9.2 支线旗标(Act 2 换色或情报回收) + +| # | 伏笔 | 埋设点(旗标) | 待回收 | 建议章节 | +|---|---|---|---|---| +| 8 | 城备净水 | B-CON-A-C(`flag_water_intel`) | "那一天"与水的关系佐证 | Act 2 推算线 | +| 9 | 市令记脸 | B-CON-A-D(`flag_shiling_noticed`) | 城内有人盯上小队 | Act 2 城内风险 | +| 10 | 鱼牙人渠道 | B-CON-B-02-A(`flag_fish_channel`) | 灰色情报网的启用与代价 | Act 2 情报线 | +| 11 | 封存的陶范密室 | B-EMO-B-B/C(`flag_sealed_vault`,"账先欠着") | 重回宫墟开启 | Act 2 重访段 | +| 12 | 徙南垣铭文 | B-CUL-A(`flag_wall_relocation`) | 城为何迁走南墙 | Act 2/3 真相链 | +| 13 | 第十位先王 | B-CUL-B(`flag_tenth_king`) | "等一位王变成先王"的现在进行时 | Act 2/3 宫廷线 | +| 14 | 守陵祖孙 | B-VAL-B(`rapport.shouling`、`flag_herb_poultice`) | 古代侧人情回响 | Act 2 古代侧 | +| 15 | 阿棠的家事 | B-ATT-B(她关频道独处) | 她在守什么私事 | Act 2 阿棠线 | +| 16 | 温简亲密度三档 | C2-05(`c2_05_depth`,沉默档明示 Act 2 兑现) | 慢线情感的兑现 | Act 2 情感线 | +| 17 | 问心幻境余波 | C3-02(`c3_02_mode`/`density`) | 幻境再入与其后果 | Act 2 幻境戏 | +| 18 | "托付那类,最不好办" | C1-03-D(`d_trust`) | 馆长对托付型玩家的态度 | Act 2 换色(小) | + +### 9.3 可选(低优先,Act 2 顺手可用,不收不算事故) + +- CW-0322 银镯(`flag_silver_bracelet`):记忆展厅陈列/征集品册复现。 +- C2-03-B 守陵人换岗观察:Act 2 陵区布控参考。 +- B-ATT-A 侧阶(`flag_side_stairs`):Act 2 重登观星台的路径换色。 + +### 9.4 Act 1 内已闭环(备查,无需后续动作) + +谶语→§3-1"禳";大火星倒计时→§3-8;问心石放置→§3-7 揭露; +哨子/绳包扣→§3-7"攥出了汗";阿棠崴脚→少年赠药;温简板子疑云→C3-06 +(深层入 #4);C-沈铎"撤离提前"→§3-8 换色。 + +> 2026-10-04 修订记录:「数你」老汉改为段内自释(夜禁城生面孔 +> 焦虑,不再跨章悬置);C1-05"安"字于 §3-1 暗门门楣回收; +> 「会唱歌的石头」在同路档内出声收口。 diff --git a/scripts/verify-adaptive.ts b/scripts/verify-adaptive.ts index d8a8c68..1320555 100644 --- a/scripts/verify-adaptive.ts +++ b/scripts/verify-adaptive.ts @@ -50,6 +50,7 @@ class MemoryStore implements EventStore { events: StoryEvent[] = []; async list(sessionId?: string) { return this.events.filter((e) => !sessionId || e.sessionId === sessionId); } async append(e: StoryEvent) { this.events.push(e); } + async purge() { this.events = []; } } class FixedJev extends MockJevClient { dimension: ProfileDimension; diff --git a/scripts/verify-live.ts b/scripts/verify-live.ts index 8bc77aa..907ef3b 100644 --- a/scripts/verify-live.ts +++ b/scripts/verify-live.ts @@ -34,6 +34,9 @@ class MemoryStore implements EventStore { async list(sessionId?: string) { return sessionId ? this.events.filter((e) => e.sessionId === sessionId) : [...this.events]; } + async purge() { + this.events = []; + } } const key = loadApiKey(); diff --git a/scripts/verify.ts b/scripts/verify.ts index 367e2d7..e709acc 100644 --- a/scripts/verify.ts +++ b/scripts/verify.ts @@ -7,7 +7,9 @@ * 5. EventStore 各实现(含 SqliteEventStore)的 append-only 性质(接口层面断言无 update/delete; * SQLite 实连只能在 Tauri 运行时内进行,Node 下不实例化)。 * 6. 同意门(ADR-0004):consent 事件存证、幂等、跨会话跳过; - * 7. 条件文本:flag 推导(附录 A)、【若】标记零泄漏、差分显隐、条件不满足节点跳过无死路。 + * 7. 条件文本:flag 推导(附录 A)、【若】标记零泄漏、差分显隐、条件不满足节点跳过无死路; + * 8. 删除全部个人数据(ADR-0004 数据删除权):purge 后事件列表为空、进度清空、 + * consent 存证删除后回到未同意态、可重新同意并继续走剧情。 * 运行:pnpm verify */ import { readFileSync } from 'node:fs'; @@ -53,6 +55,9 @@ class MemoryStore implements EventStore { async list(sessionId?: string) { return sessionId ? this.events.filter((e) => e.sessionId === sessionId) : [...this.events]; } + async purge() { + this.events = []; + } } const chapters = [1, 2, 3].map( @@ -550,6 +555,31 @@ for (const mode of ['farewell_done', 'farewell_partial', 'exit_room'] as const) check(restored.c3_02_mode === mode && restored.c3_02_fantasy_density === e.state.flags.c3_02_fantasy_density, `问心之室 ${mode}:恢复后叙事状态一致`); } +// --- 14. 删除全部个人数据(ADR-0004 数据删除权):purge 整库物理清空 + 进度清空 + 回到未同意态 --- +{ + const s = new MemoryStore(); + const progress = new MemoryProgressStore(); + const eng = new StoryEngine(chapters, s, new MockJevClient(), undefined, progress); + await eng.grantConsent(); + await walkTo(eng, 'c1-d5'); // 途经 C1-01 身份点、C1-02 讲述点、C1-03 选择点 + check((await s.list()).length > 0 && progress.load() !== null, '删除前:事件流与进度快照均非空'); + await s.purge(); + progress.clear(); + check((await s.list()).length === 0, 'purge 后事件列表为空(全部事件物理删除)'); + check(progress.load() === null, 'clear 后进度快照为空'); + check(!(await eng.hasConsent()), 'purge 后 consent 存证一并删除 → 回到未同意状态(同意门重新出现)'); + await s.purge(); + check((await s.list()).length === 0, 'purge 幂等:重复清空不报错且仍为空'); + // 删除后可重新同意并正常继续走剧情(存储清空后仍可 append,事件不串旧轨迹) + await eng.grantConsent(); + check(s.events.filter((e) => e.kind === 'consent').length === 1, '重新同意:新 consent 存证落库(只存证一次)'); + await walkTo(eng, 'c1-05'); // 从 c1-d5 出发途经 C1-04 选择点 + check( + s.events.some((e) => e.kind === 'choice') && !s.events.some((e) => e.kind === 'profile'), + '删除后可正常继续走剧情并落新事件,旧轨迹事件不残留(无已删除的 profile 事件)', + ); +} + if (failures > 0) { // 主线失败先退出,避免掩盖原有回归。 console.error(`\n${failures} 项校验失败`); diff --git a/src/App.tsx b/src/App.tsx index d0ccfb1..0dbed54 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -65,6 +65,15 @@ export default function App() { engine.replay('chapter1'); setScreen('story'); }} + onPurge={async () => { + // ADR-0004 数据删除权:事件流(含 consent 存证)物理删除、进度清空, + // 应用回到未同意状态——同意门重新出现,重新同意后从第一章开头开始。 + await store.purge(); + engine.replay('chapter1'); + progress.clear(); + setScreen('story'); + setConsent('needed'); + }} /> )} diff --git a/src/engine/eventStore.ts b/src/engine/eventStore.ts index df22887..e7f4cf4 100644 --- a/src/engine/eventStore.ts +++ b/src/engine/eventStore.ts @@ -1,14 +1,18 @@ import type { ChoiceBehavior, DimensionTag, FollowUpDimension, IdentityProfile } from './types'; /** - * 选择/讲述事件存储(ADR-0004:历史不可涂改)。 - * 接口只有 append 和 list —— 刻意不提供 update/delete, + * 选择/讲述事件存储(ADR-0004:历史不可涂改,删除权完整保留)。 + * 接口只有 append / list / purge —— 刻意不提供单条 update/delete, * 让"不允许单独编辑历史选择"成为类型层面的约束,而非约定。 + * purge 是《个人信息保护法》数据删除权(账号注销语义)下的整库物理清空, + * 不是对单条历史的修改;append-only 纪律不变。 */ export interface EventStore { append(event: StoryEvent): Promise+ 本应用只在本机记录你的剧情选择、语音讲述转写与人格画像事件,用于人格评估与伴侣匹配推荐;数据不出设备,删除即彻底消失。 +
+ + {purgeError &&删除失败:{purgeError}
} + +