来源:notes/documents/网页版笔记范围收窄与其他文档模块.md

网页版笔记范围收窄与其他文档模块

Status: resolved Type: spec

上游依据:本轮对话结论(2026-09-22);.scratch/web-note-identity-by-id/spec.md(身份改造, 本 spec 回答它的 Q1);web/docs/adr/0008(构建期产物)、0009(外壳契约)、0011(日历条目一处定义); web/CONTEXT.md(Note / Note Path / 档号)。

Problem Statement

1. 网页把整个 notes/ 目录当笔记。 产物 generated/notes.json 现在是 158 篇:111 篇在 documents/,47 篇在 sources/(25)、books/(11)、topics/(6)、projects/(4) 和根上的 knowledge_base.md。那 47 篇正文合计 5.63 MiB,占产物正文的 77%——其中最大一篇(Momenta PHIP 全文转写)1.6 MiB。它们不是正式笔记:没有 note_id,也不进日历(已实测:本地视图 / Neon / 飞书 日历三处 0 命中)。用户要求笔记模块只收 documents/

2. 身份已经准备好了,只是网页没用。 documents/ 下 114 篇全部note_id(112 篇已注册, 2 篇待处理);日程的笔记线条目本来就带 note_id(calendar_entries.id)。也就是说「笔记」与「日程」 这两个模块可以完全按 Node ID 认人,不需要 path。剩下的 47 篇没有身份,继续按 path 就行。

3. 创建时间现在取不到。 页边档号区只有「更新」(git 提交时间),用户要「文件本身的创建时间」。 实测三种取法:

取法 本机实测 在 Vercel 构建容器里
文件系统出生时间(fs.statSync().birthtime 可用,且看起来就是真实创建时间(某篇笔记 2026-06-10,BERT 全文 2026-06-06) 全部等于检出时刻:构建是 git clone,每个文件的 inode 都是那一刻建的
git 首次提交时间(git log --diff-filter=A 114 篇里 71 篇都是 2026-08-30(迁移那一刀) 可复现,但语义是「入库时间」,不是创建时间
front matter 里显式记 现在 114 篇的 front matter 只有 note_id / content_type 可复现、跨机器一致

所以「用文件本身的创建时间」要成立,必须先把创建时间写进文件本身:回填时用本机出生时间 (它是真的),之后由 note_cli 在首次创建时写入。这是 generate-notes.mjs 那条「构建期只读 notes/」 (ADR-0008)的必然结果——构建容器里没有「文件什么时候被写出来」这个信息。

Solution

1. 产物分流,两个集合一次生成。

  • notesdocuments/** 的 Markdown,带 id(= note_id)与 createdAt
  • others:其余目录的 Markdown,只有 path,没有 id。

分流发生在构建期(generate-notes.mjs),不是前端过滤:这样「笔记」的索引、搜索、计数天然只包含 documents/,前端也不需要先下载 47 篇的来源全文元数据。产物仍是一份构建快照,函数包大小不变 (7.52 MiB),变的只是服务端的取用方式。

2. 两个模块,两套身份。

模块 索引 正文 身份
笔记 GET /api/notes/api/notes/search(只含 documents/ 新接口 GET /api/notes/entry?id=<note_id> Note ID
日程 GET /api/daily/month/api/daily/day 同上面那个 entry 接口 Note ID(条目的 noteId
其他文档 新接口 GET /api/others(按顶层目录分组) 保留 GET /api/notes/detail?path=(原读取方式) Note Path

新接口叫 entry 而不是 detail,是因为它同时服务笔记与日程两个模块,「一条笔记的正文」比 「笔记详情」贴题;旧的 detail?path= 一字不改,继续给「其他文档」用。两个接口各只有一种身份, 不会再出现「一个接口两个参数谁优先」的问题。

3. 创建时间落到 front matter。

  • 回填:一次性把 114 篇的 notes/documents/** 文件系统出生时间写进 front matter created_at (本机 birthtime 可用,实测值合理)。回填脚本只补缺失的,不覆盖已有的。
  • 之后:note_cli.py create 在首次创建时写 created_at,与 note_id 一起由 CLI 生成。
  • 产物:条目带 createdAt;页边档号区从一行「更新」变成「创建 / 更新」两行。
  • 「其他文档」没有 created_at,那一行留空——不编一个假时间。

4. 兼容与代价。

  • 笔记模块的旧链接 ?n=documents/xx.md:产物里 documents/ 的条目仍然带 path,前端可在已加载的 索引里把 path 解析成 id(纯前端、一处、可删)。做不做见 Q5。
  • 旧的 /api/notes/detail?path= 仍在,只是不再服务笔记模块。
  • 日程模块的响应加一个显式字段 noteId(值就是该条目的 id),notePath 降为档号显示用。

决定(2026-09-22 用户拍板)

  • Q1 · 「其他文档」占脊上第四格:把「材料与来源」那格的占位改成「其他文档」。脊的格数与 ADR-0009 都不动。
  • Q2 · 创建时间走 front matter created_at:接受。回填前先用 scripts/check_note_created_at.py 核对,不一致的要报出来(见下)。
  • Q3 · 「其他文档」正文原样渲染:沿用同一套 Markdown 渲染,不做截断或摘要。
  • Q4 · 「其他文档」不提供搜索:只按顶层目录分组。
  • Q5 · 保留旧 path 链接兜底:笔记模块仍接受 ?n=documents/xx.md,前端在已加载的索引里 解析成 id(纯前端,一处)。

创建时间核对(2026-09-22 实测)

python3 scripts/check_note_created_at.py(读-only,报告落 config/note_created_at_report.json):

  • created_at 现在一篇都没有:115 篇 documents/ 文件的 front matter 只有 note_id / content_type。所以「文件创建时间与 created_at 是否一致」现在没有可比对象,全部是 missing (回填对象)。脚本就是为回填后验收准备的:届时不一致的行会以 mismatch 列出来。
  • 旁证比对(用文件创建时间当基准):与 git 首次提交同天 42 篇、差一天 2 篇、不同天 73 篇。 73 篇的差异全部来自 2026-08-30 那次迁移入库:57 篇创建于 2026-06、8 篇创建于 2026-07、 6 篇同月不同天(01_逐字稿--5ed3c276.md05_2025年度产品发布会_完整纯文本转写.md06_2025年度产品发布会_修订总结.md01_岗位要求逐条学习路线.md伯恩斯坦研报.md04_飞书日记采集源导入流程.md)。
  • 2 条真异常01_cc-connect_note链路迁移与lark-cli修复记录.md(birthtime 2026-09-19,提交 2026-09-18)、08_horizon2025_全文转写_paraformer-large-标点.md(birthtime 2026-09-20,提交 2026-09-19)——文件在提交之后被重新生成过,inode 是新的。这正是不用 birthtime 当长期口径的 理由:重写一次就变;created_at 写进文件之后才稳定。
  • 另:02_dg板卡X5_BPU推理服务_可视化HTML.md06_dg板卡X5_BPU推理服务_开放词表检测YOLO-World接入.md 没有注册记录,回填时只写 created_at,不动注册表。

非目标

  • 不给「其他文档」注册 note_id,不把它们塞进 notes 表或日历(这正是本次要修的错位)。
  • 不改 note_cli 的飞书三层投影,不改日历条目定义。
  • 不动 daily 的事件线,只动笔记线的深链与身份。
  • 不把 sources 下的 PDF / EPUB / MOBI 原件带进产物(一直如此)。
  • 不补那 2 篇「有 id 未注册」的笔记(06_dg板卡X5_BPU推理服务_开放词表检测YOLO-World接入.md02_dg板卡X5_BPU推理服务_可视化HTML.md)——它们属于 web-note-identity-by-id 的 Q4。

验收口径

cd codex_personal_assistant/web
npm run build
node --test tests/
npm run preview:local
  • 产物里 notes 恰好是 documents/ 下的篇数(回填前 114),others 是 47;两边 path 不重叠, 笔记侧每篇都有 id,无重复 id。
  • 笔记模块:索引只列 documents/;搜索命不中 sources 全文;?n=note_xxx 能开,旧 ?n=documents/xx.md 也能开并 canonical 成 id(Q5);页边显示「创建 / 更新」两行,创建时间与回填值 一致;scripts/check_note_created_at.py 退出码 0(无 mismatch / unreadable)。
  • 日程模块:点笔记线([笔记] xxx)用 noteId 打开正文,不经过 path。
  • 「其他文档」:按顶层目录分组列出 47 篇,按 ?path= 打开正文;该模块的请求里没有任何 id。
  • 回归:/api/notes/detail?path= 仍可用;事件线不受影响。

Tickets

# 标题 一句话
01 产物分流 generate-notes.mjs / note-artifact.mjs 产出 notesothers 两个集合,笔记侧带 id
02 创建时间落盘 核对脚本(已建:scripts/check_note_created_at.py)+ 回填(本机 birthtime → front matter created_at)+ note_cli 首次创建写入
03 新接口 GET /api/notes/entry?id= 给笔记与日程;GET /api/others 给其他文档;getNote 两条查找路径
04 笔记模块收窄 前端路由/索引/搜索只吃 documents/,旧 path 链接按 Q5 决定
05 「其他文档」模块 按 Q1 占格;索引按顶层目录分组,正文走 detail?path=
06 日程改吃 noteId daily 响应加 noteIdDaily.tsx 深链与正文都按 id
07 术语与 ADR web/CONTEXT.md 的 Note / Note Path / 档号;ADR-0009 第四格;ADR-0008 是否要提创建时间

web-note-identity-by-id 的关系

  • 那份 spec 的 Q1(非正式内容去哪)由本 spec 回答:移出笔记模块,进「其他文档」,不补 id。
  • 它的方案第 2 点「无 note_idpath: 兜底」作废:分流之后笔记模块里每一篇都有 id, 不需要兜底;others 侧按 path 认人,本来就不声称有身份。
  • 它的 ticket 06 由本 spec 的 ticket 01 / 05 取代。

Comments

  • 2026-09-22:spec 新建,状态 needs-triage
  • 2026-09-22:Q1–Q5 全部拍板(第四格放「其他文档」、创建时间走 front matter、正文原样渲染、 不搜索、保留旧 path 兜底)。创建时间核对脚本 scripts/check_note_created_at.py 已建并跑过一次, 结论见「创建时间核对」一节。下一步可转 ready-for-agent 开 ticket。

Answer

2026-09-22 全部落地,Status: resolved

创建时间(ticket 02)

  • scripts/backfill_note_created_at.py(dry-run 默认)回填 115 篇 documents/created_at, 值取本机文件出生时间;重跑零变更(已有 created_at 不动)。
  • scripts/check_note_created_at.py 验收:115 篇全部 一致,退出码 0。报告在 config/note_created_at_report.json
  • scripts/note_cli.py 现在会写 created_at(新笔记取当天),并在重同步时沿用文件里已有的值, 不会被重新同步重置。

产物与接口(ticket 01、03)

  • generate-notes.mjs 产出两个集合:notes 115 篇(documents/,每篇带 idcreatedAt)、 others 47 篇(按 path)。构建期断言:documents/ 下的笔记缺 note_id 或 id 重复即失败。
  • 新接口 GET /api/notes/entry?id= 服务「笔记」与「日程」;GET /api/others 服务「其他文档」; 原 GET /api/notes/detail?path= 保留,但只服务「其他文档」(传 documents/ 路径返回 404)。
  • GET /api/daily/* 的笔记线条目新增 noteIdnotePath 降为档号显示)。

前端(ticket 04、05、06)

  • 脊上第四格由「材料与来源」落成「其他文档」(ADR-0009);笔记模块只列 documents/ 的 115 篇。
  • 路由:?n= 装 Note ID,其他文档用 ?o= 装 Note Path;旧 ?n=documents/xx.md 由前端在已加载索引里 解析成 id 并改写地址栏(实测可用)。
  • 页边档号区:笔记是「档号 / 创建 / 更新」,其他文档是「档号 / 分类 / 更新」。

验收记录npm run build 通过;npm test 53/53;npm run linttsc -b 干净; npm run preview:local + Playwright 实测——笔记 115 篇、其他文档按 来源25/书籍11/专题6/项目4/知识库1 分组、旧 path 链接 canonical 成 id、日程笔记线深链落到 ?n=note_2972af60fe554c7b,无 console 错误。

文档(ticket 07)web/CONTEXT.md(Note ID / 其他文档 / 档号 / 创建时间)、 docs/adr/0012(新增)、0009(第四格)、0010?n= 换身份)、docs/operations.md(接口与构建约束)。