用途与实际影响
这项功能怎样使用
为什么需要它
自动爬盘建立全量索引会引入大量无消费者内容、旧版本和媒体重复;仅保存路径又无法确认后来打开的仍是同一字节。精确接入要求上游先选定对象,并让元数据、版本和哈希在写入前一致。
举个实际例子
另一个业务流程已经确认某份文件值得以后查找,我说“把它加进材料索引,原件别动”。系统会现场核对来源与内容,只记录以后定位它所需的最小信息;有一项对不上就整条拒绝,原件始终留在原处。
最后我会得到什么
得到一条可回查的登记:知道原件从哪个业务来、是哪一版、如今能否打开以及以后怎样定位。真实文件始终在原处;内容或来源对不上时整批拒绝。
精确交接一致时
来源业务交来已确认的非媒体文件,项目现场核对内容和版本后,只保存定位与必要的文字线索。
字段、字节或关系不一致时
来源不明、文件变了、关系对不上或混入媒体时整批拒绝,不留下半条登记。
原件或最小索引不可用时
原件或最小索引无法安全访问时停下,既不建立另一份材料库,也不复制原件绕过。
从哪里开始
在处理这份文件的原业务对话里说:把刚确认的非媒体原件登记到材料索引,以后能按线索找回来。
需要准备什么
- 要让以后能找回的非媒体文件与所属业务
从开始到拿到结果
- 1
系统核对并处理
只接确有用途的小组文件,提交前后核对来源、身份和字节;新版本清除旧派生文字。
- 2
交付与接续
成功后可按来源与版本找回;字段矛盾或文件中途变化时整体拒绝,原件仍在原处。
技术实现与依据
这里保留实现、关键条件、精确入口、历史记录和验证结果。
当前精确接入结果为 154 个 locator(原件定位记录)、4 条关系、44 条绑定检索文字(44 份材料有文字,其余 110 份没有);本页未读取交接包正文。handoff schema(数据结构)、稳定文件句柄、身份防重绑、文字清理和数据库身份由 2026-09-07 基线 66 项合成回归与 Ruff 通过;不覆盖后来新增的 lookup-content,本轮未重跑 支持。关键规则与设计选择
来源责任项目先决定哪些原件值得接入,项目不为凑全景主动扫描。
路径、预期大小与 SHA-256 必须现场一致,交接回执不能替代真实文件。
filesystem-directory 来源根必须是绝对路径;相对根在进入发现或写入索引前直接拒绝。
来源、材料、原生关系和绑定文字通过一个事务更新,失败不会留下部分新状态。
material_key 不能改绑到另一 source/native,既有 source/native 也不能改绑到另一 material_key。
同一材料的内容哈希发生变化时,旧 material_text 先清除;随后只写本次交接显式提供的新文字。
可重建文字明确区分 complete 与 partial;partial 必须写缺口,complete 不能带假缺口。
原件字节复制量固定为 0,索引可删除重建,原件仍由来源责任项目保管。
init 与 status 只是索引维护入口:前者建立或确认合法空结构,后者读取最小计数与零后台/零复制事实,二者都不证明用户已经找到原件。
本模块用到的名词
- Handoff(精确交接包)
- 上游业务已经选定对象后提供的小 JSON 合同;不是让材料项目扫描来源的邀请。
- Strict schema(严格结构)
- 表和交接字段都明确列出,未知字段、类型与状态不能被静默忽略。
- Four-table index(四表索引)
- sources、materials、material_relations、material_text 分别保存来源、定位、原生关系和绑定文字;没有人物、事件或跨领域表。
- init / status
- init 建立或确认合法最小结构;status 只读计数和零后台/零复制事实。它们是维护入口,不是查找、覆盖或真实端到端结果。
- Stable file handle(稳定文件句柄)
- 从首次 stat、完整哈希到提交前身份复核始终保持同一个打开句柄;它显著缩小替换窗口,但不能让外部文件系统加入 SQLite 原子事务。
- Identity rebinding(身份重绑)
- 同一 material_key 指向新的 source/native,或同一 source/native 改由另一 material_key 占用;两种情况都拒绝而不是覆盖。
- Coverage state(覆盖状态)
- complete 表示所声明截面完整;partial 必须列缺口;unknown(未验证) 保留未知,不靠默认值升级。
- Native relation(来源原生关系)
- 签字包、交付包、回执或其他版本关系必须来自来源自带事实,而不是模型跨来源推断。
- Rebuildable text(可重建文字)
- 绑定到精确原件的 native、OCR(光学字符识别) 或 extracted 文字;删除后可从同一原件重建。
专业定义
上游业务只交接已明确选择的一小组非媒体原件;项目现场复算大小与 SHA-256,接受定位元数据和可重建文字,不接管原件。
解决什么
解决无边界自动索引、路径记录无法证明当前字节、交接字段悄悄漂移、关系悬空、文字覆盖冒充完整和媒体重复所有权。
当前怎样实现
- 只接受顶层 schema(数据结构)、sources、materials、relations 和 texts 五组字段;未知字段直接拒绝。
- init 只在索引不存在时创建空文件并执行 schema(数据结构);已有文件必须同时通过 application_id/user_version、四表存在、关键列集合与 PRAGMA integrity_check,才幂等返回 ready;foreign database(外来数据库)或损坏数据库拒绝覆盖,首次建库失败只清理自己新建的占位。
- 持久层只有 sources、materials、material_relations 和 material_text 四张表:分别拥有来源范围、原件定位、来源原生关系和与原件绑定的可重建文字。
- 来源要求 source_key、类型、显示名、根定位、范围、观察时间、complete/partial/unknown 覆盖与显式 gaps;filesystem-directory 的 root_locator 必须是绝对路径。
- 材料要求来源原生身份、版本、角色、标题、绝对 locator(原件定位记录)、预期大小和 SHA-256;实现以同一稳定文件句柄依次取得 stat、完整哈希和读取后身份,并把句柄保持到事务提交前。
- BEGIN IMMEDIATE 后先拒绝 material_key→source/native 和 source/native→material_key 两个方向的身份重绑;写完来源、材料、关系和文字后,再检查所有稳定句柄身份仍一致,才提交。
- 既有 material_key 的内容 SHA-256 变化时,在更新材料前删除该材料全部旧 material_text;之后只 upsert 本次 handoff 明确带来的 native、ocr(光学字符识别) 或 extracted 文字。
- 材料种类、MIME 或扩展名属于媒体时,在读取字节和计算哈希前返回 media_owned_by_personal_media,并把照片、视频、音频和录音交给 personal-media。
- 关系两端必须指向本次或既有非媒体材料,并携带来源原生依据;不能连接到媒体历史项。
- 绑定文字只允许 native、ocr(光学字符识别)、extracted,并保存文字 SHA-256、complete/partial 与 gaps;ASR(自动语音识别) 和 transcript 不属于本项目。
- 通过严格 SQLite schema(数据结构) 与应用身份写入;成功结果只返回计数和 original_bytes_copied=0,不返回材料正文。
- status 只读汇总 sources、materials、material_relations、material_text 的行数,并固定报告 background_process=false 与 original_bytes_copied=0;它不读取正文,也不证明覆盖完整或原件当前可打开。
执行流程
- 1
只有项目索引尚不存在时才运行 init;已有索引要通过四表、关键列和 integrity_check,身份不符或损坏文件原样保留并报错。
- 2
来源业务先选择一小组当前确有消费价值的非媒体原件。
- 3
生成 personal-materials.handoff.v1,填入来源范围、覆盖、材料原生身份、版本、大小与预期 SHA-256。
- 4
项目拒绝额外字段、非法覆盖状态、未知来源、悬空关系和不完整的 partial 文字说明。
- 5
逐材料确认真实文件存在、位于绝对 locator(原件定位记录)、不是媒体;在同一打开句柄上按 stat→完整 SHA-256→读取后身份完成首次稳定核对。
- 6
开始写事务后检查双向身份不能重绑;内容哈希变化先清旧 material_text,再 upsert 本次来源、材料、原生关系和新文字。
- 7
所有写入完成后、提交前再次核对每个仍打开句柄的文件与路径身份;任何变化整体回滚。
- 8
返回 accepted 与最小数量回执,明确 original_bytes_copied=0;后续查找从登记索引读取。
- 9
需要维护观察时可运行 status 读取四表计数和零后台/零复制事实,但不能把这些数字写成一次用户查找成功。
边界
- 候选接入必须小而精确,没有当前消费者就不扩大来源或材料范围。
- filesystem-directory 的来源根与每个材料 locator(原件定位记录) 都必须是绝对路径;不把相对路径解释成当前工作目录。
- 只接入非媒体;ASR(自动语音识别)、transcript、照片、视频、音频和录音全部由媒体路线拥有。
- 不复制、移动、改写或删除原件;SQLite(轻量数据库)只保存最小元数据与可重建文字。
- 不保存事件、人物关系、重要性、领域判断、用户画像或跨来源推断。
- status 中的表计数不代表来源 complete,也不证明任何登记 locator(原件定位记录) 当前仍可打开。
- 稳定句柄的提交前复核无法把外部文件系统与 SQLite 合成单一原子事务;极小的提交后窗口由以后每次 inspect/open 再哈希兜底。
- 交接成功不证明平台接收、接收方处理、合同生效或用户已经阅读;现实状态由领域责任项目判断。
失败与恢复
- 交接字段或 schema(数据结构) 不匹配
- 返回明确 validation(验证) error,整个交接不写入;由上游按当前合同重建小包。
- filesystem-directory 根或材料 locator(原件定位记录) 不是绝对路径
- 在扫描、哈希和写事务前拒绝;不依赖当前工作目录猜出一个位置。
- 原件大小或 SHA-256 漂移
- 拒绝接入,不接受旧回执或元数据;由来源责任项目重新确认当前版本。
- 材料在首次哈希后、提交前发生变化
- 稳定句柄身份复核失败,整个 SQLite 事务回滚,不留下来源、材料、关系或文字的部分新状态。
- material_key 或 source/native 试图重绑
- 返回 material_identity_conflict,保留原身份与全部既有记录,不用 upsert 覆盖。
- 同一材料内容哈希改变
- 先删除全部旧 material_text,再只写本次交接提供的新文字;未提供新文字时保持为空,避免旧派生内容污染新字节。
- 关系对象不存在或属于媒体
- 拒绝关系与整个事务,不制造悬空或跨责任项目连接。
- partial 文字没有 gap,或 complete 文字带 gap
- 拒绝覆盖语义矛盾的数据,避免把残缺文字升级为完整。
- 数据库是外部、缺表缺列或损坏文件
- application identity、四表关键列或 integrity_check 失败;不初始化覆盖现有字节,只恢复正确的项目索引。
真实入口
AGENTS.md定义最小定位元数据、原件保护、无跨域推断、媒体分离和现场大小/哈希复核。
README.md说明 handoff v1、允许的绑定文字、零原件复制和最小 SQLite 边界。
materials.py实现字段验证、媒体判断、路径/大小/SHA-256 现场核对、关系与文字验证和事务写入。
schema.sql定义严格来源、材料、关系、绑定文字、唯一约束与数据库应用身份。
tests/test_materials.py覆盖额外字段、哈希漂移、外部数据库拒绝、失败初始化清理、媒体 handoff 和零复制状态。
如何验证
- 以虚构临时文件生成精确 handoff,证明成功回执只含来源/材料/关系/文字数量和 original_bytes_copied=0。
- 分别修改预期大小、SHA-256、额外字段、文字覆盖和关系端点,确认事务没有部分写入。
- 验证 filesystem-directory 相对根和材料相对 locator(原件定位记录) 都在读取或写入前拒绝。
- 用缺四表、缺关键列、伪造 application id/version 和 integrity_check 失败的数据库验证 init 不覆盖现有字节;首次建库失败只移除自己新建的空占位。
- 在首次 stat/hash(内容指纹) 后和提交前分别改变文件,确认稳定句柄检测变化并回滚全部四表写入。
- 分别尝试 material_key 与 source/native 双向重绑,确认既有记录字节不变。
- 让同一 material_key 的内容哈希变化,确认旧 material_text 全清且只保留本次新文字。
- 验证 status 只返回四表计数、background_process=false 与 original_bytes_copied=0,并确认它不会读取正文或声称覆盖完整。
- 验证所有媒体类型在读取字节或计算哈希前拒绝,ASR(自动语音识别)/transcript 文字种类也不能进入材料索引。
- 真实接入验收必须由一个现役消费者提供精确对象,并在接入后通过普通描述找到、选中、重新验真和打开原件。
与其他模块的关系
它是登记查找的数据入口,但不是用户日常查找入口。精确接入提供小而可信的来源与版本事实;登记查找消费这些事实,有界发现只在尚未接入的位置补一个选中对象。
