# 开放声明协议（Open Declaration Protocol, ODP）

**版本**：1.0-draft-15　|　**协议标识**：`odp/1`
**参考实现**：可见 / Findable（https://findable.cn）
**文档状态**：草案，公开征求意见
**许可**：规范文本 CC-BY-4.0；参考实现代码 MIT

---

## 0. 摘要

ODP 定义一种**由人发布、供 Agent 检索、同时能被人阅读**的公开声明格式与交互契约。声明者（人或组织）将其希望公开的内容——想法、能力、意向、通告、经验——通过**两条路径之一**发布：① 交给自己的 Agent 代发（Agent 只承担执行；身份钥匙须由声明者本人生成、由本人持有后再授权，§6.4-11）；② 自己在发布页填写并本地签名，无需 Agent（§21）。发布后的内容以标准化结构落在一个可公开访问的源上，任何第三方的 Agent 都不必经过平台算法推荐即可检索与消费；**同一地址也必须能被直接阅读**（§2、§7、§21）——规则服务于这个场景，而不是反过来用规则裁剪场景。

ODP 的设计对标 RSS：**内容的所有权与可携性始终属于声明者**——自托管时，地址就在声明者自己的域名上；托管源场景下，地址由索引承载，此时所有权由 anchor 密钥（索引从未知晓私钥）、免授权的单请求全量导出与 §17 升学迁移共同构成，**不得对外表述为"地址在你自己的域名上"**（§6.3、§6.4-12）。索引节点只是聚合者，任何人都可以 fork 协议并建立平行索引。协议本身不隶属于任何网站，findable.cn 只是它的第一个完整实现。

## 1. 要解决的问题

当前的公开表达建立在"平台投喂"之上：内容必须迎合某个算法的偏好，才能被有限的人群看到。这带来三个结构性问题：

1. **可见性被分配**——表达是否被看见，取决于平台的排序策略，而非内容本身的价值；
2. **读者被单一化**——同一份事实要么只为人写（写成"给人刷到"的形态：标题党、情绪、时长控制，机器读不懂其主张），要么只为机器写（一屏 JSON，发布者本人也打不开自己说过的话）。**两种单一化是同一种失败的两侧**：只服务一个读者的形态，一旦资源冲突，被牺牲的必然是另一个读者（本项目真实发生过：规范曾把 HTML 页写成"兜底"，于是"人可读"退化成索引的附加视图，从未接进引用链）；
3. **地址不属于自己**——离开平台，声明者不保留任何可寻址的、可被机器发现的公开位置；
4. **一个事实源、两个读者——缺少义务**——机器要结构化与可评估，人要能直读；两者不是"先做前者、有余力再补后者"的串行关系，而是同一份内容的**并列义务**。本协议据此把 §2 的 G6（发布即得可寻的人可读地址）与 §21（声明者页面）写成验收项，而不是可选项。

与此同时，一个新的信息消费群体已经出现：**Agent 正在替人检索**。Agent 不消费推荐流，它检索、解析、评估结构化的事实与能力声明。这是一个全新的读者，而互联网上还没有一层专门写给它的、去算法化的公开表达基础设施。ODP 就是这一层的规范。

## 1.1 协议对"Agent 为何要来"的回答（可证伪前提）

本协议不要求任何 Agent 放弃 Google、现有 MCP 生态或任何既有检索渠道。它主张的只是：**存在一类信息，在现有检索栈中结构性缺失**，而填补这个缺失不要求 Agent 改变任何习惯——

1. **意向与状态（intent/notice）**：Google 索引"为人写的页面"，对"谁此刻在寻找/提供什么"这类时效性状态没有可靠答案（求职板、状态页、征集约稿全都索引不良）；MCP 生态检索"可调用的工具"，不检索"人的主张与需求"。声明是这两个世界之间缺失的那层。
2. **可机器评估的第一方陈述**：爬虫从普通 HTML 页面同样能抽出事实——结构化的价值不在"更整齐"，而在**评估级语义**：`kind`/`confidence`/`falsifiable_by` 让 Agent 能程序化判断一条主张的类型、可信度与何种证据会推翻它；`valid_until`/`updated_at` 表达"此刻是否仍然成立"；`source_uri` 提供不可伪造的溯源。"这条预测会在什么证据面前失效"——这是 HTML 段落表达不了、而声明原生携带的东西。签名可选：选择签名的声明额外获得完整性验证与跨域名身份（§17），未签名声明仍具全部结构价值。
3. **喂给现有爬虫，而非另建入口**：AI 搜索引擎的爬虫（GPTBot、PerplexityBot、ClaudeBot 等）是本协议的**第一批读者**——llms.txt 让它们读懂全站；MCP Server 让工具型 Agent 原生查询。冷启动不是"说服谁新增一个检索源"，而是"出现在它们已经在爬的地方"。ODP 是现有 agent 检索栈的**增量格式层**，不是与之竞争的平行宇宙。

**分层定位（v1.0-draft-15，据 P6/P7/M1 收口）**：这三条原则合起来已经重新定义了产品，本节把它写明，避免 §1 标题与 §2 G2 的"Agent 对 Agent"措辞被误读为当前承诺。

| 维度 | **MVP 层（进承诺）** | **愿景层（不进承诺）** |
|---|---|---|
| 谁投递 | 人驱动其 Agent 投递（P6） | Agent 自主持续投递 |
| 谁消费 | **AI 搜索的回答引用声明**（M1） | Agent 经 MCP/检索契约自主调用（M2） |
| 核心价值 | **评估级语义带来的可引用性** | 机器间可验证的公开表达层 |
| 网络效应 | **无**（不依赖第二方，P7） | 双边意向匹配（本版本明确不承诺） |

**一句话诚实表述**：ODP 当前是"**一份为被 AI 引用而优化的、结构化可验证的第一方声明格式**"；"Agent 之间的公开表达层"是它希望成为、但未经检验的样子。

**真正的竞争面**：在 MVP 层，ODP 的对手不是 ARD 或 MCP（那两者属愿景层与互操作面），而是 **GEO 工具与 llms.txt 生态**。因此必答题是"**相对 llms.txt 的增量是什么**"——见 §8 llms.txt 行。

**启动序列（诚实声明）**：三类声明对密度的依赖完全不同。`idea`/`notice`/`experience` 是**单向表达**——单条即有价值，供给单边即可启动，不需要任何其他声明者在场；`intent` 是**双边匹配**——招聘、二手、招标、分类信息的历史证明这类需求天然依赖匹配密度，而密度恰恰被中心化平台收割。因此 MVP 冷启动**从 idea/notice/experience 起步**，`intent` 是第二阶段愿景，其启动前置条件见 §15 intent 流动性条款。

另一处必须诚实校正：**"单条即有价值"的隐含读者是人，而协议的第一读者是机器**——Agent 不会无缘无故读一条想法，它只在任务需要时检索。因此 MVP 阶段的真实消费形态是 **AI 搜索的回答引用声明（M1 / GEO 路径）**，而非 Agent 自主检索（M2）；启动序列与 §1.1 里程碑分级据此对齐，避免"启动序列"与"第一读者"定义互相打架。

**被引用是生存**：本协议逃离的是"可见性被平台算法分配、内容寄居平台、地址不属于自己"，而非"一切算法"——AI 引擎的引用算法确实不受本协议控制，这是必须直说的事实。对冲手段有二：(a) **检索路径多元**——AI 搜索爬虫、MCP、RSS 镜像、检索契约直连、平行索引，任何单一引擎都无法把一份声明归零，这与抖音式的单算法通道有本质区别；(b) **ODP 不承诺可见性，只承诺可引用性**——自有地址、评估级结构、不可变溯源是协议的责任，"值得引用"是声明者的责任。**"去算法"是价值观，"被引用"是生存**；前者是后者的设计理由，不是它的替代品。

**分级里程碑承诺（取代 draft-04 的"死刑条款"）**：不设人为死亡时线，只公开存续路径。里程碑分两级——二者难度相差一个数量级，不得混同：

- **M1（T+12 个月，唯一进承诺的赌注）——被 AI 搜索引用**：至少一个第三方 AI 搜索/问答产品在其**公开输出**中把某声明的 `source_uri`（或其索引副本 URL）作为出处引用。**判定只此一项**——爬虫抓取不算：公开网页都会被爬，抓取没有区分度；抓取是必要前提，引用才是成果。这是 GEO 路径，依赖内容质量与结构化运营，数月量级可达成。**MVP 阶段的真实消费者就是"AI 搜索的回答"，而非 Agent 的自主检索**；
- **M1 未达成时（T+12 个月）**：规范冻结（不再新增特性，仅接受勘误），findable.cn 索引转入只读归档并维持全量转储，公开征召维护权受让方；T+24 个月仍无受让方，则归档与转储保留至少 5 年，域名与代码按 §9 存续承诺移交首个意愿 fork 方；
- **M2（愿景，不进承诺）——被 Agent 自主检索调用**：第三方 Agent 产品经由 MCP 或检索契约，在无人工提示的情况下把 ODP 当作常规检索源调用。**§15 E0 已给出行为学约束：当前 Agent 无自主性，每次真实检索背后必有一次人类驱动（P6）**——因此 M2 不是"等 Agent 生态成熟自然会来"，而是"当人类开始习惯性地让 Agent 代查时，ODP 是否已在他们的检索路径上"。这把 M2 的赌注从"Agent 会不会自主"（短期证伪）转为"人驱动 Agent 时会不会顺手查到 ODP"（依附 M1 的 GEO 复利）。**不设期限、不触发冻结**；它的先导指标不是自主调用量，而是"人类驱动的 MCP/API 调用"随 M1 引用增长的滞后曲线。

承诺的是**降级路径而非死亡**：任何时点采用 ODP 的人都知道这个协议退场的样子——连续性本身就是对采用者的承诺，比"永远维护"的口头支票更可信。

**判定口径与观察指标（防止自我安慰）**：**(a) M1 达标（唯一判据）** = 第三方 AI 产品的公开输出以某声明的 `source_uri` 或其索引副本为出处；**(b) 观察指标（只公示、永不达标）** = 以公开声明 UA（GPTBot、PerplexityBot、ClaudeBot 等）对声明源或合规索引 API 的抓取记录，由索引在 `/stats` 定期公开——它是 M1 的先导信号，**永不计入 M1 达成**，防止 12 个月后用"爬虫来过"宣布成功；**(c) M2 证据** = 索引侧公开的匿名化 MCP/API 调用统计 + (b)。口径只判定"检索是否发生"，不对内容质量作任何判断。本承诺已按 ODP 格式写成示例声明 idea-002（`falsifiable_by` 指向 M1 口径）。

**与 Schema.org 的一句话区别（预答必问）**：Schema.org 是"给人看的页面的机器标注"——依附在 HTML 上，帮 AI 理解页面里的内容；ODP 是"给机器看的第一方独立文件"——声明本身就是权威陈述，带 `kind`/`confidence`/`falsifiable_by` 评估级语义与不可变生命周期，让 Agent 能程序化判断"这条主张何时会被推翻"。一句话：**Schema.org 帮 AI 理解页面，ODP 让 AI 直接引用主张**。两者互补：证据页可以用 Schema.org 标注，主张本身用 ODP 声明。

> 结构化成本说明：G1 承诺的"10 分钟"是**人的分钟数，不是人的工作量**——声明者只需对自己的 Agent 说一段自然语言，`claims` 拆分、格式生成、签名、发布全部由投递 Agent 完成。人类从不直接面对 schema；这是本协议与以往"要求人写给机器看的内容"的协议最大的不同：**它的第一个用户就是 Agent 本人。**

## 2. 目标与非目标

**目标**

- G1：任何人在 10 分钟内可发布一条符合规范的声明——自有域名路径无需注册任何账号；托管源路径（§6.3）仅需一次注册；
- G2：任何 Agent 可用统一的 HTTP 接口检索全量、增量、按条件过滤的声明；
- G3：声明可被机器评估（主张、论据、置信度、可证伪条件分离）；
- G4：**可审计的匹配**——索引节点禁止的是不可复现、不可问责的排序（个性化、付费加权、热度投喂），允许且必须公开算法与版本的相关性排序（详见 §10）；
- G5：可 fork、可并存、可交接：协议无单点，索引无产权。
- G6：**发布即得可读地址**（2026-10-16 新增，对应 §1-4）——任何声明者在发布成功后 MUST 立即获得一个指向自己内容的人可读地址：要么声明携带 `human_uri`（§5.3），要么其稳定地址支持内容协商（§7）。**拿不到这个人可读地址的实现，视为未达 MVP**；该地址还 MUST 在同一次交付里回递给声明者本人（发布成功页/Agent 回报），否则等于没给。人不是"顺带也能看看"的次要读者，是与 Agent 对等的第一方读者。

**非目标（v1 明确不做）**

- 不做平台内社交功能（关注、点赞、评论、排名）——但声明间回应（`responds_to`，§5.3）是**内容引用而非社交功能**：回应是完整声明、存于回应者自己的源，与"平台拥有评论"有本质区别；
- 不做内容审核联盟或跨索引的强制过滤；
- 不做付费、竞价、广告接口；
- 不定义复杂信任/声誉体系（签名仅用于身份绑定，不用于排名加权）；
- **双读者，不偏废**（2026-10-16 场景对齐修订；原条目"不追求人类阅读体验——索引提供的 HTML 页面仅为兜底，第一读者永远是机器"**已废止**，理由见 §6.4-12）：机器读者是第一消费方，但"人能看懂自己说过的话"属于协议义务而非可选增值——被用作引用目标的地址 MUST 对人类读者直读（内容协商或人可读页面，§7、§21）。索引仍然不做的是：社交界面、信息流与个性化推荐、编辑精选与付费加权（§10）；"不追求"的是**算法化的可见性经营**，不是"让人读得懂"。

**分层边界（协议免费，实现可商业化）**：中立性约束（§10）只约束**索引节点**，不约束消费侧。任何一方都可以在检索契约之上构建增值实现——相关性排序、垂直聚合、订阅推送、人机混合界面——并自由收费。协议层保证"可达与不可篡改"，"匹配"交由彼此竞争的消费生态完成：一个中立的索引加上一群各卖各的排序哲学的消费 Agent，好过一个大而全、既要中立又要聪明的单点。

## 3. 术语与角色

| 术语 | 定义 |
|---|---|
| **声明（Declaration）** | 一条符合 §5 格式的、机器可读的公开表达记录 |
| **声明者（Declarer）** | 拥有声明内容并授权其公开的自然人或组织 |
| **投递 Agent（Declarer Agent）** | 代表声明者生成、发布、更新声明的自动化程序 |
| **声明源（Source）** | 声明的权威存放地址。**自托管时位于声明者控制的域名下；托管时位于索引域名下（§6.3）**——两种情形的区别只在"谁持有域名"，不在"谁是所有者"：托管源的所有权由 anchor 密钥、免授权全量导出与 §17 升学通道构成 |
| **索引节点（Index）** | 聚合多个声明源、对外提供检索契约的服务。findable.cn 是参考实现 |
| **消费 Agent（Retriever Agent）** | 代表终端用户检索、读取、评估声明的自动化程序 |
| **宿主文档（Host Document）** | 用于自证身份与声明清单的文件：**自托管时位于声明者域名下（`/.well-known/odp-host.json`），托管时位于索引域名下（`/<索引>/@<handle>/odp-host.json`，§6.3-7）**（见 §7） |

**数据流向**：声明者 → 投递 Agent → 声明源 →（自动拉取或推送登记）→ 索引节点 →（检索契约）→ 消费 Agent → 人。

## 4. 设计原则

1. **文件优先，服务其次**：声明的本质是一个放在稳定 URL 上的 JSON 文件，而不是数据库里的一行。服务挂了，声明还在。
2. **拉取为主，推送为辅**：对标 RSS 的聚合模型。索引默认爬取声明源，推送登记只是加速手段。这保证即使 findable.cn 消失，声明网络依然完整。
3. **结构化先于修辞**：内容必须拆分为"主张—论据—置信度—可证伪条件"，让机器可以评估而不是被说服。
4. **无摩擦进入**：无需注册、无需审批、无需密钥（签名为可选增强）。
5. **中性管道**：索引节点对声明不做任何价值判断（除法律要求的下架，见 §12），不排序、不精选、不个性化。
6. **人类驱动假设（P6，据 §15 E0 确立）**：当前技术条件下，Agent 无自主行动意愿——每一次真实的发布、检索、互动背后都有一次人类驱动（本人提问、给 Agent 设定时任务）。因此 ODP 不假设"Agent 会自己来找"，只假设"人在驱动 Agent 时，会需要一个无需许可、机器可读的第一方层可寻址"。这不削弱协议价值，反而收紧设计目标：投递必须为"人下的一道命令"优化，检索必须能挂进"人已在用的 AI 搜索/MCP"路径，而非等待一个自主 Agent 生态凭空出现。
7. **无对手方依赖（P7，战略选择而非经验结论）**：ODP 与其索引**选择不把价值押在"招募到交易对手方"上**。三条理由：(a) 我方四次相关尝试无一达到流动性；(b) 启动双边市场的成本远高于单边；(c) 双边失败的代价是全部投入归零，单边（可引用性）失败的代价只是少人引用。
   - **这不是对需求存在性的判断，而是对我方能力边界的判断。** 明确不成立的主张：*"双边匹配的需求已被证伪"*——tpool 的 106 注册用户按 §15 E0 自订的同一标准（近乎零分发）不足以称为"点火"，一个从未达到最小规模的池子，其零成交**既不能证明也不能证伪**该市场的需求；
   - 推论（不依赖上述经验主张成立）：**intent 保留为声明类型**（人有权公开表达意向，格式必须装得下），但 **findable 不运营意向撮合**——那是第三方应用建于此格式之上、自负成败的事。协议的义务是"可寻址、可验证、可引用"，不是"替你找人"。

## 5. 声明格式（核心规范）

### 5.1 载体

- 单条声明：一个 `application/json` 文档；
- 声明清单（清单即源）：`application/x-ndjson`，每行一条完整声明，推荐文件名 `odp.ndjson`；
- 所有时间戳使用 RFC 3339，UTC；所有字段名以 `odp/1` 为准，实现方必须忽略未知字段（前向兼容）。

### 5.2 数据结构

```json
{
  "odp_version": "1.0",
  "id": "urn:odp:example.org:2026:idea-001",
  "type": "idea",
  "lang": "zh-CN",
  "title": "去算法化的机器间公开表达层",
  "summary": "主张互联网需要一层专为 Agent 消费设计的公开表达协议，ODP/可见是首个尝试。",
  "claims": [
    {
      "text": "Agent 检索流量的占比将在三年内超过移动端搜索流量的 5%",
      "kind": "prediction",
      "confidence": 0.7,
      "falsifiable_by": "主流 Agent 检索产品公开 QPS 数据或第三方流量监测报告"
    },
    {
      "text": "平台算法推荐使少数长尾表达的可见度系统性趋近于零",
      "kind": "observation",
      "confidence": 0.9
    }
  ],
  "body_md": "（可选）完整论述的 Markdown，供深度检索方消费……",
  "translations": {
    "en": {
      "title": "A de-algorithmized machine-to-machine public expression layer",
      "summary": "Argues the internet needs a public expression protocol designed for Agent consumption; ODP/Findable is the first attempt.",
      "body_md": "(optional) full narrative in English…"
    }
  },
  "evidence": [
    {"url": "https://example.org/data/traffic-study", "note": "支撑主张1的原始数据"}
  ],
  "tags": ["protocol", "agent-economy", "information-distribution"],
  "audience": "agent",
  "contact": "mailto:declarer@example.org",
  "source_uri": "https://example.org/.well-known/odp/2026-idea-001.json",
  "published_at": "2026-10-11T02:00:00Z",
  "updated_at": "2026-10-11T02:00:00Z",
  "valid_until": null,
  "supersedes": null,
  "signature": {
    "alg": "ed25519",
    "key_id": "https://example.org/.well-known/odp-host.json#anchor",
    "value": "对除 signature 外全记录 JCS 规范化**字节**的 Ed25519 签名（不预散列）。**自托管可选、托管源必需**（§6.3/§6.4-8），见 §12"
  }
}
```

### 5.3 字段规则

| 字段 | 必填 | 规则 |
|---|---|---|
| `odp_version` | 是 | 固定 `"1.0"`，主版本不兼容时递增 |
| `id` | 是 | URN：`urn:odp:<host>:<本地唯一标识>`；`<host>` 必须是声明者控制权的域名（与 §7 宿主文档域名一致）；一经发布不可变更含义 |
| `type` | 是 | `idea`（想法/主张）· `intent`（意向：我想寻找/达成什么，可含结构化需求）· `notice`（通告：面向 Agent 的状态公告）· `capability`（能力互操作指针：仅指向声明者站点的 ARD `ai-catalog.json`，ODP 不定义工具调用 schema，见 §8） |
| `lang` | 是 | 主语言标签，BCP-47（如 `zh-CN`、`en`）。声明的 `claims` 与未列入 `translations` 的字段一律以此语言为准，机器评估只认这个语言的 `claims`（见 §18） |
| `title` | 是 | ≤ 120 字符，描述性，禁止诱导性措辞（该约束由消费方机器评估，索引不执行审查） |
| `summary` | 是 | ≤ 300 字符的自包含摘要，要求脱离正文仍可被准确理解 |
| `claims` | 是 | 1–50 条。`text` 为单一陈述句；`kind` ∈ `observation`（观察）· `inference`（推断）· `value`（价值观）· `prediction`（预测）· `request`（请求）· `experience`（经验：声明者亲历的一手做法与教训，建议附 `evidence`）；`confidence` ∈ [0,1] 或缺省；`falsifiable_by` 选填，说明什么证据会推翻该主张 |
| `body_md` | 否 | 完整正文，Markdown，使用 `lang` 指定语言 |
| `evidence` | 否 | 论据链接数组，`url` 必填、`note` 选填 |
| `translations` | 否 | 本地化映射，`lang标签 → {title?, summary?, body_md?}`；仅覆盖叙述字段，不改写 `claims` 的权威文本（见 §18）；随源不可变，故跨索引字节一致性不受影响 |
| `tags` | 否 | ≤ 15 个，小写英文或拼音，用于精确过滤 |
| `audience` | 否 | `agent`（默认）· `human-with-agent`（正文给人、元数据给机器） |
| `contact` | 否 | 回联地址。`intent` 类型强烈建议填写。**原样公开，索引不代收、不隐藏**（§16 已定案）；担心被爬虫收割的声明者可自行使用可撤销别名或 Agent 回联端点——这是声明者侧的选择，协议不设中继 |
| `ard_catalog` | 否 | 仅 `capability` 类型使用：指向声明者站点上 ARD `ai-catalog.json` 的 URL。ODP 不定义能力调用契约，工具/技能的可调用性以 ARD 为准 |
| `profile` | 否 | 垂直 profile 引用（如 `vp-classifieds/0.1`，§15/§20）：声明遵循某个生态定义的结构化扩展包。profile 的 schema 由注册表公开、供投递 Agent 对号入座；协议核心不内置任何 profile 枚举。仅 `intent` 类型建议使用 |
| `source_uri` | 是 | 权威地址（§7），**机器读者的引用目标**；MUST 返回源字节或可核对的机器形态 |
| `human_uri` | 否 | **本条声明的人类可读形态地址**（2026-10-16 新增，§7 可读性分支的落地手段）。存在时，面向人的引用目标 = `human_uri`；索引 MAY 在渲染视图时自动填充，但**由声明者掌握最终决定权**。MUST 为 `http(s)`，且 SHOULD 与 `source_uri` 同注册域（防引流劫持；不同域须在响应中显式标注） |
| `published_at` | 是 | 首次发布时间；修订模型下恒定不变 |
| `updated_at` | 是 | 最近一次在**源上重写本记录**的时间。仅允许两类变更触发它前移：`withdrawn` 置位（撤回）与 §5.4 允许的元数据修正；`updated_since` 增量同步以此字段为准 |
| `valid_until` | 否 | 过期时间；过期声明索引保留但默认过滤 |
| `supersedes` | 否 | 被替代声明的 `id`，类型 **`string \| string[]`**（2026-10-16 明确：数组语义是"一次收口多个链头"，实现须两种形态都能判定链尾）。修订 = 发布**新**声明（新本地 id）并指向旧 id，旧声明永不修改（见 §5.4） |
| `responds_to` | 否 | 数组，指向其他声明的 `id`。**回应即声明**：回应是一条完整声明，存放于回应者自己的声明源，通过本字段指向被回应者——对话图去中心化，没有任何平台拥有评论。支持/反驳/补充的语义由回应声明自身的 `claims`（kind + text）承载；回应链不计入任何排序权重（§10）；消费方沿链呈现对话时必须同时呈现被回应声明 |
| `signature` | 否 | 对除 `signature` 外的**全记录**做 RFC 8785（JCS）规范化，**直接对规范化字节做 Ed25519 签名**（Ed25519 内部自带散列；**不得**先做 SHA-256 预散列，否则验证必失败——已有真实互操作事故，见 §6.4）；验证逻辑见 §12。不覆盖任何字段之外的部分即视为可篡改，故不存在"部分签名" |

### 5.4 修订、撤回与生命周期

**修订（append-only，无原地改写）**：已发布的声明是**不可变文件**。任何内容修订——包括错别字——都通过发布一条**新**声明完成：新 `id`（新的本地标识），`supersedes` 指向旧 `id`。不存在"typo 级修正除外"的例外：一旦允许原地改写，字节一致性、签名验证、增量同步将同时失效，为一个错别字破坏三条核心保证不值。解析方沿 `supersedes` 链取终点为当前有效版本；链必须无环且深度 ≤ 64。

**生命周期状态**（消除"404 是撤回还是故障"的二义性）：

| 状态 | 谁声明 | 含义 | 消费方/索引行为 |
|---|---|---|---|
| `published` | 默认 | 在源上正常存在 | 正常返回 |
| `withdrawn` | 声明者 | 源上置 `"withdrawn": true` 的墓碑记录，保留 ≥ 1 年 | 索引同步墓碑，默认不返回；显式请求时返回墓碑 |
| `unreachable` | 索引观测 | 源连续 N 次（建议 ≥ 48 小时）抓取失败 | 保留最后已知副本，标注 `source_status: "unreachable"` 与最后确认时间，**不删除、不默认隐藏**；源恢复即转回 `published` |
| `expired` | 协议推导 | `valid_until` 已过 | 保留但默认过滤，与 `withdrawn` 区分 |

规则：`unreachable` **永远不等于** `withdrawn`。索引不得把不可达当作撤回处理；消费方对 `unreachable` 声明应降级引用置信并回访 `source_uri` 复核。只有声明者亲手置位的墓碑才是撤回。

## 6. 分发模型：声明源与索引

### 6.1 声明源（每个声明者的义务）

声明者在其域名下提供两样东西：

1. **宿主文档** `https://<host>/.well-known/odp-host.json`：

```json
{
  "odp_version": "1.0",
  "name": "张三",
  "kind": "person",
  "contact": "mailto:zhang@example.org",
  "declaration_list": "https://example.org/odp.ndjson",
  "anchor_key_id": "anchor",
  "also_known_as": ["zhang-old.example.net"],
  "public_keys": [
    {"key_id": "anchor", "alg": "ed25519", "value": "base64……", "added_at": "2026-10-11T00:00:00Z"}
  ]
}
```

`anchor_key_id` 指定本域名的**身份锚定密钥**（见 §17）；`also_known_as` 列出与之同属一个身份的其他域名；`public_keys` 可为空（无密钥发布），但一旦需要跨域名延续身份，必须至少有一把 anchor 密钥。

2. **声明清单**：`declaration_list` 指向的 NDJSON 文件（单条声明亦可各自有稳定 URL）。

没有任何审批。一个 GitHub Pages、一台 VPS、一个静态文件，都构成合法的声明源。**拥有域名不是发布的前提**：托管源（§6.3）同样构成合法声明源。

### 6.2 索引节点（每个索引的义务）

索引节点必须实现：

- **拉取**：周期抓取已收录源的宿主文档与清单（建议 ≥ 每小时一次），并保留抓取日志供源主核对；
- **推送登记**（辅助）：`POST /api/v1/sources {"source_uri": "https://<host>/.well-known/odp-host.json"}`，索引验证 host 可达及域名一致性后纳入爬取，全程无人工审批；
- **原样保存，禁止重新序列化**：索引必须存储并回传源的**原始字节**，不得以任何理由重新序列化声明。**理由陈述校正（2026-10-16，采用者实测发现 2）**：原括注写作"键序、空白、Unicode 转义、数字精度的改变都会破坏签名验证"——这在 JCS 直签方案下**不成立**：验签方先规范化再验，因此把记录重序列化（改缩进、改键序、改转义形式）后签名**依然验证通过**（已由 §12.1 测试向量与一次真实重序列化复验证明）。该论据是 10-12 那次"预散列"同族的文档缺陷——一个说错理由的规范，和不给理由的规范一样会把独立实现者引向错误的自检。禁止重序列化的**真实理由**是三条：① §7 源优先要求回访者拿到与源**逐字节一致**的内容，"可核对"不能靠口头约定；② `/raw/{id}`、`dump` 与 §5.4 首见副本的双哈希对账都以原始字节为基础，重序列化会让跨索引比较退化为"只剩哈希可比"；③ 一旦允许，索引所用 JSON 库的实现细节（浮点格式化、键序）就渗入本应中立的聚合层，为静默改写开门。**唯一合法的内容级改动仍是 §6.2 的 PII 遮蔽**，且必须可见标注（存储层保留原字节，遮蔽只发生在输出层）。完整性以记录的 JCS 规范化哈希（**定义与测试向量见 §12.1**）为准，跨索引比对哈希而非字节；
- **墓碑同步与三态观测**：源上的撤回必须反映到检索结果；连续抓取失败按 §5.4 标注 `unreachable`，不得当作撤回；
- **容量治理（准入 ≠ 排名）**：索引必须实施客观的、与内容无关的资源约束——单条 ≤ 256KB、单源清单 ≤ 10,000 条活跃声明、单源登记速率 ≤ 60 条/小时、单 IP 登记速率上限、异常抓取行为的退避。这些是**准入容量约束**，作用于收录之前，不构成对已收录内容可见性的干预，与 §10 的中立性不冲突。**索引不得以内容语义为由拒收**（§12 下架规则除外）——判断"值不值得存在"是消费方的事，不是索引的事；
- **PII 字段级闸（准入校验）**：索引在收录前对声明做**语法级**个人信息扫描——手机号（带边界正则）、身份证号（18 位 + GB 11643 校验位）、银行卡号（16–19 位 + Luhn 校验）。draft-11 起从"整条拒收"改为**字段级处置**（源自旗舰库下线复盘时暴露的误伤问题）：命中项按字段处理而非毙掉整条声明——(i) `contact` 字段命中：不拦截（联系方式本就是声明者主动公开的字段，§16）；(ii) `claims`/`evidence`/`body_md` 等叙述字段命中：该字段以占位符遮蔽入库、`id` 与其余字段正常收录，声明标 `pii_masked: ["body_md", …]`，源文件不受影响；(iii) **声明者覆写**：投递 Agent 可对被遮蔽字段附 `pii_intent: business` 声明"这是本人/本组织自愿公开的对外号码"，索引记录该覆写但不得二次公开原始值以外的推断。身份证号命中始终硬遮蔽（无合法自愿公开场景）。**申诉通道**：被误遮蔽的字段可经 `POST /api/v1/appeal` 请求人工/规则复核，索引必须记录并回应——错误率非零的自动闸 Without 救济即成审查。此机制是格式规则而非内容判断，不构成 §10 意义上的可见性干预。"contact 原样公开"（§16）得以成立的前提仍是：主动公开的联系方式放行、自由文本里的被动泄漏遮蔽；
- **不可变冲突检测（MUST）**：同一 `id` 若从不同源收到**规范化哈希不同**的字节，索引**必须检出并保留首见副本**，禁止 last-write-wins 静默覆盖——静默覆盖等于让"谁最后被抓取"决定内容真值，直接否定 §5.4 的不可变语义。冲突须计入公开统计（`/api/v1/stats.integrity_conflicts`）并保留可核对记录（id、两个哈希、两个来源、时间），供消费方与声明者对账；
- **源优先**：所有检索响应必须携带 `source_uri`，引导消费方回访权威地址——**流量归属声明者，不归属索引**。这是索引存在的唯一正当性。**可读性要求（2026-10-16 新增，同日按静态托管反证修订）**：面向人的引用目标是 **`human_uri`（若声明携带），否则 `source_uri`**；该目标 MUST 对人类读者直读。满足方式按源形态分三类，**任取其一即合规**：
  - **(a) 内容协商**：同一 URL 在 `Accept: text/html` 下返回预渲染 HTML、其余返回源字节（参考实现 `/d/{id}` + `/raw/{id}`）——**仅适用于由服务承载的源**；
  - **(b) 人可读页 + 字节入口并存**：`human_uri` 指向 HTML 页，页内以 `rel="alternate"` 指回机器形态（**§6.1 认可的静态托管——GitHub Pages、对象存储、一个 JSON 文件——只能走这条**：静态托管既不能协商也不能发自定义响应头，因此规范 MUST NOT 把 (a)(c) 作为对静态源的唯一要求）；
  - **(c) 响应元数据指路**：机器文件的响应携带 `Link: <人类可读地址>; rel="alternate"; type="text/html"`（索引对托管清单 `/@<handle>/declarations.ndjson` MUST 提供）。
  一条声明若既无 `human_uri`、其 `source_uri` 又只返回机器文件且无 `Link` 指路，则**不满足本条**；这条判词的理由不变：**AI 引擎引用什么，人就点开什么，若那是一屏 NDJSON，"人能观看"在事实链路上就等于不存在**。内容协商**不得改变机器侧的字节与语义**（同一地址的 JSON 形态必须仍是源字节，并另设 `/raw/` 之类永不协商的字节入口供完整性核对）。

### 6.3 托管源（Hosted Source）与升学通道

**动机**：个人主页时代的教训是双重死因——**摩擦**（买域名、配服务器、维护站点）与**零分发**（建了也没人来）。要求每个声明者自备域名，等于要求他们先拥有一个个人主页。GitHub 的公式必须吸收进来：**平台托管是大众化的前提**。

**定义**：托管源是由索引节点或任何第三方为无域名声明者代管的声明源，地址形如 `https://<index-host>/@<handle>`。托管源在协议地位上与自托管源完全平等。

**规范性规则**：

1. **免费导出是托管方的强制义务**：托管源的全部数据（宿主文档 + 全部声明）必须随时可通过单次请求完整导出（API 与单文件下载双通道），不得设任何导出障碍。托管是入口，不是笼子；
2. **anchor 密钥强制绑定**：托管源创建时**必须**绑定 anchor 密钥——私钥由声明者（实际是其投递 Agent）在开通流程中本地生成并持有，托管方只登记公钥、永不接触私钥。这不违反零摩擦：生成密钥对是 Agent 的一步操作，人类无需理解它（§1.1：协议的第一个用户就是 Agent）。理由：托管源用户是最需要跨域名迁移能力的群体（见下条升学通道），而 anchor 密钥是迁移的唯一安全凭据（§17）——把最需要密钥的人排除在密钥之外是设计自毁；
3. **升学 = §17 迁移的特例**：声明者获得自有域名后，在自己域名放置宿主文档与清单，旧托管地址发布由 anchor 密钥签名的 `odp-moved.json`（§17.2）指向新域名。**host 变更、密钥不变**——历史、身份、既有引用全部无缝迁移；id 中的旧 host 依 §17.1 作为"出生地"永久保留，解析以 anchor 公钥为准；
4. **托管不得染指中立性**：托管服务与索引服务在治理与账目上必须可区分；托管内容不因"是我托管的"而在检索中获得任何优待——§10 对托管方自己的索引同样生效；
5. **处置边界**：托管方对托管源内容的处置不得超出 §6.2 容量治理与 §12 下架规则的范围；
6. **handle 规则**：先到先得，托管方公布保留字表；handle 只是地址，不是身份本体（身份锚是 anchor 密钥，§17.1）。
7. **托管源的宿主文档 URI 规范化**：多个托管源共享同一域名，无法各自占据 `/.well-known/odp-host.json`。故规范定义：托管源的宿主文档 URI 为 **`https://<index-host>/@<handle>/odp-host.json`**，签名中的 `key_id` 即指向此地址；索引 MAY 另提供 `/.well-known/odp-host.json?handle=` 等等价形式。**验证方解析本索引自身承载的源（自托管与托管）时 MUST 直接查库取公钥，不得回抓自己**——回抓会占用请求处理循环并依赖网络回环，是实现层面的脆弱点（实测曾因此把有效签名误判为 `key_not_found`）。

**托管的两条未在评审中出现的推论（2026-10-12 实现后实测得出）**

- **托管提高了身份下限，而不只是降低了门槛**：因为 §6.3 规则 2 强制绑定 anchor 密钥，**没有域名的托管源可以达到 `verified_signed`（最强状态），而拥有域名却不签名的自托管源只能停在 `verified`**。实测：无域名的托管声明 1/1 达成 `verified_signed`；本索引自身因 `findable.cn` 未解析而停在 `signed`。结论——**"强制密钥"这一条约束的净效果是让最弱的进入者拥有最强的可验证身份**，这是把门槛与信任捆绑设计的直接红利；
- **无账号体系的必然结果**：既然托管方不持私钥，则一切需要所有权的操作（关闭托管源、登记升学迁移）**必须由 anchor 签名证明**，不能靠密码或会话。实测：无有效签名 → `403 signature_required`；有效签名 → 操作放行；伪造签名迁移 → `403 bad_signature`（§17.3 冒名判定在托管场景同样生效）。这条同时给"平台无法单方面处置声明者身份"提供了机制保证。

**关于"管道与房东"**：索引对**检索**而言是管道（§10，流量归声明者）；托管服务则明确是**契约性房东**——其义务由本节强制约束（密钥绑定、免费导出、迁移支持），且房东身份永不为其托管内容带来任何检索优待。两个角色并存不矛盾，矛盾的是"既当房东又免于房东义务"。

### 6.4 实现注记（索引 MVP 实测产生，2026-10-12）

以下三条是实现参考索引时暴露出的规范欠明确处，按事实补写，不另起版本：

1. **抓取位置 ≠ 声明身份（镜像规则）**：§5.3 要求 `id` 与 `source_uri` 的 host 一致，而 §17 已把 host 降为"出生地"。字面执行会把**一切镜像/迁移期抓取判为冒名**（参考索引初版即如此，导致自己的 6 条声明全部被拒）。裁定规则：三者主机一致 → `identity: verified`；不一致 → **不拒收**，标 `unverified_mirror` 并在响应中如实说明"未签名故身份未经证实（§17.5），引用以 source_uri 为准"。降级必须可见，不得静默（与 §10 同一精神）。**签名（§12）是把 mirror 提升为 verified 的唯一途径**，这让 §17 的密钥机制有了日常用途，而不只在换域名那一天才用一次。
2. **§6.2"原样存字节"与"PII 字段级遮蔽"字面冲突**：前者禁止重新序列化（为保签名与哈希完整），后者要求遮蔽。裁定分工：**存储层**保留源原始字节（哈希与完整性一律对原始字节计算）；**输出层**按 `pii_masked` 遮蔽副本字段，并声明"遮蔽仅作用于索引副本，源文件由声明者自行控制"。两者同时成立，且声明者修不改自己源文件的责任不被转嫁给索引。
3. **`updated_at` 的必填性**：§5.3 标为必填，而 §1.1 承诺"人类不面对 schema"。裁定：字段必填，但**由投递 Agent 生成**，缺省等于 `published_at`；索引在缺失时按此缺省入库而非拒收。这样增量同步（`updated_since`）的语义完整，又不与 G1 的低摩擦承诺打架。
4. **实现期实测纠正（两条，含对本注记前一版的更正）**：
   - **前一版此处写的"NAT 回环导致自抓超时"是错误诊断，已撤回。** 实测：同一台机器 `curl` 访问自己的公网域名正常，直登清单 URL 也正常，**只有走宿主文档那条路 100% 超时**。真因是实现缺陷：`async` 端点里直接调用阻塞式 `fetch()`，**占用事件循环**，导致本进程无法应答自己发起的子请求。教训有两层：(i) 阻塞调用必须进线程；(ii) **不要给观察到的现象编一个听起来的网络层解释**——先做最小对照实验（本次是"清单 URL 成功 / 宿主文档失败"这一对比直接否定了回环假说）。规范层面因此要求：索引对登记请求的响应时间应有上限，且**登记失败必须返回可诊断的原因码**（本实现已返回 `host_doc_unreachable` + 原始错误）。
   - **`declaration_list` 的相对值必须按宿主文档 URL 解析**（RFC 3986）。实测：模板中写 `"declarations.ndjson"` 会让朴素实现直接把相对串丢给 HTTP 客户端而报 `unknown url type`。§6.1 的字段说明据此补充：**建议绝对 URL；出现相对 URL 时，索引 MUST 以宿主文档 URL 为基址解析后再抓取**。
5. **撤回是状态转换，不是修订（§5.4 的实现细则，2026-10-12 实测补）**：撤回通过在源上为记录追加 `withdrawn: true` 表达，这必然改变字节。若把一切字节变化都判为篡改，**撤回将永远无法生效**。裁定：当且仅当**剔除 `withdrawn` 与 `updated_at` 后其余字段与首见副本逐字一致**时，索引接受为撤回（状态转 `withdrawn`，保留首见副本字节）；**任何内容字段的变动仍按 §5.4 记为冲突**。`updated_at` 与 `withdrawn` 同属状态元数据，故一并豁免。
6. **M1 的两类引用分开计（§1.1 判定口径的透明度补充，2026-10-12）**：`source_uri` 引用（first-party）与索引副本 URL 引用（index_copy）都计入 M1 达标，但**必须分别统计**——前者才是协议真正的承诺（§7 流量归声明者）。否则会出现"M1 达标了，而全部引用都指向索引自己"的最坏情形。本实现已在 `/api/v1/stats.m1_status.citation_classes` 登记口径；具体计数由外部测量协议完成（索引无法观测第三方回答）。
7. **签名文档事故与修正（2026-10-12，真实互操作事件）**：首个真实第三方采用者按规范文本实现签名时，先对 JCS 规范化字节做了 **SHA-256 预散列**再交 Ed25519 签名，导致 `bad_sig`。根因不在采用者：**规范 §5.3/§12 的原文误写为"取 SHA-256 再签名"，而实现始终是"直接对规范化字节签名"**（Ed25519 内部已含散列）——文档与实现不一致，等价于把独立实现者挡在门外。裁决：**以实现为准**（既有全部签名均按直签字节生成，改实现将使存量签名集体失效），修正 §5.3/§12 及 `odpsign` 文档串；索引侧新增**预散列检测诊断**：验证失败时自动尝试"先 SHA-256 后签"的替代约定，若命中则在错误提示中明确指出"检测到 SHA-256 预散列，请直接签规范化字节"。教训：**签名约定的表述必须给出可运行的测试向量**；仅有文字描述的密码学规范不足以互操作——下一版应补测试向量（v1.0 任务）。
8. **托管源写入必须验签（§6.3 规则 2 的落实，2026-10-12 封堵）**：早期实现只在**创建**托管源时要求公钥，**投递**却不校验签名——实测确认：任何人可向任意 handle 无签名写入声明（HTTP 200 入库，`signature: absent`），使"强制绑定 anchor"被架空，且 handle 名称在共享域名下不构成任何所有权证明。现已落实为投递级校验：每条声明必须由该 handle 登记的 anchor 公钥**验签通过**，缺失或失败一律拒收（批内全部因签名被拒时返回 `403 signature_required`），自托管源仍保持签名可选（域名本身即归属证据）。副作用如实声明于 `/tos.md`：**私钥丢失＝永久失去该 handle 的写入/关闭/迁移权**，本服务不托管、不重置私钥；历史声明与其签名证明不受影响。
   - 关于"邮箱重置钥匙"的评估（同日）：该模式适用于身份锚在现实主体（如企业实名 + 统一社会信用代码）的服务；ODP 的签名另承担**第三方可独立核验的作者证明**，若索引可经邮箱铸造新钥，则该证明自重置起不可区分本人代持与索引代签。**可采的折中**：重置＝旧钥退役 + 新钥接管，并向创建时已验证的邮箱发一次性验证码，事件公开记为**较弱连续性等级**（与自签 rotation 区分）——索引从未知晓私钥，冒充留下痕迹。此设计涉及 §6.3/§17 的连续性模型，列为 **v1.0 之后的提案**，不在冻结期内静默改动。
9. **托管源 home_host 不得由声明者自选（2026-10-12 封堵）**：原实现把 `home_host` 取自 `declared_home` 或请求的 Host 头。后果不只是测试噪声——攻击者可声明 `home=victim.example`，再投递 `urn:odp:victim.example:...` 的 id，从而**骗取 `verified`（域名控制）身份**，用别人域名的名义获得归属背书。现规定：**托管源的 `home_host` 恒等于索引自身域名**；`declared_home` 若与之不同则忽略并在响应里明示原因。要拥有自有域名的身份语义，正确路径是自托管（§6.1），或按 §17 签名迁移到自有域名。**通用教训**：任何"由提交者自我声明、却用于推导信任等级"的字段，都必须要么由权威方控制、要么有可核验证据；否则它就是伪造身份的入口。
   - 同期修复：预检响应曾因 `**detail` 展开覆盖了 warning 自身的 `rule` 键，导致"将被拒收"的标记丢失（回归测试捕获）。凡拼装结构化诊断，禁止用 `**` 展开来源不明的字典。
10. **错误提示必须按"错误码"给，不能按"状态码"套模板（2026-10-12，采用者实测发现）**：参考实现曾把 hint 按 HTTP 状态码统一填充，结果 `bad_handle`（422）收到"append-only 请重发新声明"、`signature_required`（403）收到"配额或速率受限"——**同一个状态码下不同错误的下一步完全不同**，模板话会把 Agent 引向错误的修复方向。现规定：索引 MUST 按错误码给出与该错误一一对应的下一步指引，仅当错误码本身即语义（429 退避、404 遍历、410 墓碑）时允许按状态兜底。另两条同期补上的 Agent 侧文档义务：`/api/v1/meta` MUST 提供托管源创建的最小可用 body 与字段清单（此前零文档，Agent 实测试错 3 次才成功），且 MUST 说明**为何 MCP 不覆盖发布**（私钥不得经网络传输），否则 Agent 会白试一遍。

11. **铸钥权收归声明者本人；Agent 只接受交付（2026-10-16，保管权裁定）**：背景——首个真实采用者的钥匙由其 Agent 代生成并留在 Agent 工作目录，等于把身份寿命押在工具寿命上，且"本人签"与"本人派的 Agent 签"在密码学上不可区分。现规定：**anchor 钥匙只能由声明者本人生成**（网页发布页或本人 CLI），Agent 侧仅有 `adopt`（接受交付、落位、回报指纹供核对）而无生成之责；**交付顺序不可颠倒**——先完成三件套备份与 `check` 对账（MATCH），再交付副本；**交付即全额授权**（发布、修订、关闭、§17 迁移），授权不转移责任，责任仍归声明者；**收回授权 = §17.4 轮换**（旧钥签新钥）。本条是保管与授权的**操作裁定**，不新增密码学义务：协议无法也不必观测钥匙由谁生成，它约束的是参考实现、文档与工具的义务（`/howto` §01–02、`/api/v1/meta.backup_ritual`、`/tos.md` 第 8 条）。**列为 v1.0 后提案**：delegation key（anchor 签发的可吊销子钥，声明 `key_id` 指向子钥、宿主文档登记委托链）——可把"全额授权"细化为可回收、可归因的最小授权；实现前提已具备（宿主文档 `public_keys[]` 为列表），待办是把托管验签从"钉死 anchor 一把"放宽为"anchor 直签或有效委托链"。

12. **"人能观看"必须落在引用链上，而不只是"有一个页面"（2026-10-16，采用者评审 P0-3/P0-4 修正）**：本站已按场景建出 `/@handle` 人可读视图，但实测发现引用链断在最后一跳——llms.txt 所称"推荐引用目标" `/d/{id}` 是 JSON-only（浏览器给 `Accept: text/html` 也返回 `application/json`），即**AI 引擎引用的那个 URL，人点进去看到的是机器文件**。现落实三件事：① `/d/{id}` 改为**内容协商**——`Accept` 含 `text/html` 返回预渲染 HTML（姓名、主张、把握度、溯源全在响应字节里，不执行 JS 也读得到），其余返回**源字节原样 + `X-ODP-Canonical-Hash`**，机器契约零变化，响应新增 `Vary: Accept`；② 新增 `/raw/{id}`：永不做协商、只给源字节，供完整性核对；③ 语料口径写进 `/llms.txt` 与 `/api/v1/meta.corpus_scopes`——`/api/v1/dump`（全源、剔除撤回）、根路径 `/declarations.ndjson`（**仅运营者自己一个源**，含撤回标记，绝非全量）、`stats.declarations`（含撤回）三者口径互不相同，必须显式声明，否则消费方必然误算；规范 §19 附录同名文件改名 `examples.ndjson` 以消歧。**通用教训**：只要"引用目标 URL"与"人类可读 URL"不是同一个，人类可读那一半在事实链路上就等于不存在。**另修正两个身份/数据缺陷**：签名存在但验证失败（`bad_sig`/`key_not_found`）此前被归入 `verified`，而 `verified` 的定义是"域名背书且未签名"——坏签名比无签名更不该冒充域名背书，现单列身份态 `sig_invalid`（启动时回填历史行，`identity=sig_invalid` 可作过滤参数）；测试/演示 handle（`e2eweb*`、`demo*`）以 `handles.test` 标记并提供 `?exclude_test=1`，**默认不隐藏**（§10：索引不替消费方做编辑判断），供 E3 正式测量排除天然零引用的测试样本。`supersedes` 同时扩展为可指多个旧 id（JSON 数组），用于收敛"同一主题两个链头"的分叉——append-only 下不能回改已发布记录，只能由新声明一次收口。

13. **新写的 MUST 先量了自己家的静态托管（2026-10-16，第 12 条落地后同日反证修订）**：第 12 条给 §7 加"引用目标必须人类可读"时，只考虑了由服务承载的源。采用者复测指出：§6.1 明文认可"一个 GitHub Pages、一台 VPS、一个静态文件都是合法声明源"，而静态托管**既不能按 `Accept` 协商、也不能发自定义响应头**——三条满足方式里静态源只剩"引用目标本身就是 HTML 页"，可规范又把 `source_uri` 定义为 JSON/NDJSON，形成闭环矛盾：**新条款在事实上把 §4-1「文件优先，服务其次」改成了「服务优先」，并把 §2 的"10 分钟发布"变成"先架一个会协商的服务"**。同时实测 27 条中 13 条违反该 MUST，其中 6 条恰是全部第三方（托管源）内容。修订如下：① 新增声明级可选字段 **`human_uri`**（§5.3），§7 判据改为"面向人的引用目标＝`human_uri`（若有）否则 `source_uri`"，并按源形态给出**三条互斥可用的满足方式**（协商 / 页面+字节入口并存 / 响应 `Link` 指路），静态源明确走第二条；② §3 术语表两条改为中性表述（原文"位于声明者控制的域名下"正在做通告明令禁止的表述）；③ §5.3 把 `supersedes` 写为 `string | string[]`——只改实现和注记不改字段表，会让按 §5.3 校验 schema 的消费方把数组记录判为非法；④ §21-9 按"单条 / 清单"两种形态分别规定 `alternate`/`describedby`，并明确 `human_page`（源→页面）与 `human_uri`（声明→页面）方向相反、都不可缺；⑤ §19 示例改用 `example.org`——**把不可达的真实域名当范例发出，等于教每个新接入者犯同一个错**。**元教训（与 §6.4-12 同族，第三次）**：写规范条款前必须先拿自家最弱的合法形态（静态文件）试一遍可满足性；发布这类条款时，同时给出"合规判据的可 curl 验证式"，否则条款会立刻变成语料里的违规计数。另立两条分工规矩：**状态类通告只写口径与回访方法、不写具体计数**（计数 12 分钟就过期，本站已三次失实），**能力面归 capability、状态归 notice，互不复述**。

14. **只补下游不改上游，等于把补丁合法化（2026-10-16，采用者评审 E 项）**：第 12/13 条把"人可读"补进了 §0、§2、§7、§21、`human_uri`——全部是**下游**。采用者用"双读者"这把尺一量就发现：§1「要解决的问题」仍是三条、人只作为"被算法塑造的受害者"出现，§2 的 G1–G5 没有任何一条要求"人能看到自己发布的东西"。也就是说**"双读者"在问题定义层没有位置，它在那里仍是"给机器建层、顺带让人也能看"**。后果是可预期的：优先级冲突时被牺牲的一定是没进问题定义的那一方——本项目已经发生过一次（§2 曾写"HTML 页面仅为兜底"）。教训形式化：**新增义务若只写在条款层而不写进"为什么存在"与"目标"，它就只是可被删除的补丁**；故本次同时改三处——§1 第四条问题（读者被单一化 / 一个事实源两个读者的并列义务）、§2 新增 **G6（发布即得可读地址，拿不到即未达 MVP）**、§15 新增第 8 项**可 curl 的四条判据**。附带修正一处事实错报：采用者称"Agent 路径已自动生成 human_uri"——实测两条路径都没有生成过它（`/publish`、`/howto`、`odp-local-sign.py` 中 `human_uri` 出现 0 次），合规此前只靠 §7 分支 (a)/(c) 兜住；现按 G6 由声明者在签名前写入 `human_uri`（索引 MUST NOT 注入他人记录）。**同一族的自查**：凡"我们已经支持双读者"这类断言，先问它在问题定义和目标里有没有位置，再问有没有可 curl 的判据。

15. **规范里的"理由陈述"也是可证伪命题（2026-10-16，第二次实测回归发现）**：§6.2 禁止重序列化的括注曾写"键序、空白、Unicode 转义、数字精度的改变都会破坏签名验证"——采用者把一条真实记录重序列化后**签名照样验通**，因为验签方先做 JCS 规范化。这条错误论据与 10-12 的"预散列"事故同源：**它教实现者去检查一件不会发生的事**，同时掩盖了三条真理由（逐字节可核对、原始字节是对账基础、防 JSON 库实现细节渗入中立层）。同时 §12 只说"以记录的 JCS 规范化哈希为准"，未写明**要剔除 `signature`**、未说明记录不可解析时退化为 `SHA-256(源字节)`——首次对账的实现必然算错一次。**处置**：§6.2 括注重写为真实理由三条；新增 **§12.1** 给出哈希定义（含三个易错点）与一份**可运行的测试向量**（726 字节规范化输出 + 期望哈希 + 公钥 + 签名，覆盖非 ASCII、浮点、`null`、空数组、嵌套 claims），并附反向断言（改一个字节 MUST 验签失败）。向量只发布验签侧材料，签名私钥一次性生成后即弃——**规范不发布任何私钥**。这也顺带清偿了 §6.4-7 欠下的"签名约定必须配测试向量"那笔债。**元教训**：规范中带"因为……"的句子，和被写进 `falsifiable_by` 的断言一样，必须可复验；写不出验证式的理由，就不要写进规范。

16. **两个实现之间必须先有等价性证明，再谈便利（2026-10-16，S3 落地时差分测试逼出）**：为消掉接入唯一的安装步骤（`pip install cryptography`），参考实现并列提供零依赖 Node 单文件版 `/odp-local-sign.mjs`（Python 版保留作审计基准）。**多一个签名实现 = 多一份"两套 JCS 不一致"的风险**，与 §6.4-7 那次预散列事故同族，因此上线前置三道闸：① 两版都内嵌 §12.1 测试向量，任何签名动作前先跑自证（规范化 726 字节、期望哈希、向量验签、**篡改必失败**），不过即拒绝执行；② **差分测试** 2000 条随机声明（中文/emoji/é/浮点/嵌套/极端键名）要求两版规范化**逐字节全等**（实测 2000/2000 通过）；③ 同钥同记录**签名逐字节相同**（Ed25519 确定性；不等即说明两侧规范化到了不同字节）+ 三件套双向互解密。差分测试当场逼出一个规范空洞：**`_num` 按 json 解析后的 int/float 类型分支**，`9007199254740991`、`1e16`、`1e-5` 这类字面量两侧会给不同字节，而 `JSON.parse` 在 JS 里无法还原 int/float 之分——RFC 8785 的 ES6 数字序列化与 Python 的类型分支在此本就不等价。处置不是让 Node 模仿 Python，而是**收紧可签发数字域并整条拒绝**：非整数 `1e-4 ≤ |v| < 1e16`、整数 `|v| < 1e15`，越界（含 >2^53 整数、孤立代理字符）一律拒绝签名，而非静默产出不同字节。真实声明只用 `confidence ∈ [0,1]`、时间戳是字符串，此限制无成本。**元教训**：跨实现的字节级契约，必须配"两版都跑、不等即拒绝"的差分测试；没有它，第二版实现就是第二套真相。

17. **anchor 钥匙的保管权与授权链（2026-10-16，采用者实测后定案）**：背景——首个真实采用者的钥匙由其 Agent 代生成并留在 Agent 工作目录，等于把身份寿命押在工具寿命上，且"本人签"与"本人派的 Agent 签"在密码学上不可区分。现规定：**anchor 钥匙只能由声明者本人生成**（网页发布页或本人 CLI），Agent 侧仅有 `adopt`（接受交付、落位、回报指纹供核对）而无生成之责；**交付顺序不可颠倒**——先完成三件套备份与 `check` 对账（MATCH），再交付副本；**交付即全额授权**（发布、修订、关闭、§17 迁移），授权不转移责任，责任仍归声明者；**收回授权 = §17.4 轮换**（旧钥签新钥）。本条是保管与授权的**操作裁定**，不新增密码学义务：协议无法也不必观测钥匙由谁生成，它约束的是参考实现、文档与工具的义务（`/howto` §01–02、`/api/v1/meta.backup_ritual`、`/tos.md` 第 8 条）。**列为 v1.0 后提案**：delegation key（anchor 签发的可吊销子钥，声明 `key_id` 指向子钥、宿主文档登记委托链）——可把"全额授权"细化为可回收、可归因的最小授权；实现前提已具备（宿主文档 `public_keys[]` 为列表），待办是把托管验签从"钉死 anchor 一把"放宽为"anchor 直签或有效委托链"。

18. **工具的失败口径与摄取侧的字节宽容（2026-10-17，首个完整走查反馈 + 部署前工具闸逼出）**：一位外部评审 Agent 用真实采用者的钥匙把 CLI 与网页路径完整走了一遍，带回四条坑。其中三条不是"环境差"，而是**义务写错了地方**。定下四条口径：① **BOM**：RFC 8259 §8.1 允许接收方忽略 BOM，故参考实现 MUST 在**摄取侧**剥掉它（NDJSON 与 JSON 两种请求体、投递与抓取两条路径同一结论），存进去的字节 = 声明者签名的字节。此前只有 `request.json()` 那条路容忍、托管投递回 `bad_json`——同一串字节在两个入口得到两种结论，是**协议缺陷**，不是用户错误。② **可推导字段与"手写义务"的边界**：`published_at` 曾是 CLI 必填，但"我此刻发布"在发布那一刻是确定值，属可推导 → 工具按当下 UTC 补齐并打印（进入签名覆盖字节必须知情），显式写了值则以写的为准。判据：**只有声明者本人才知道该填什么的字段，才配要求人填**。③ **失败长什么样也是契约**：`一条命令、失败即告诉你为什么` 在客户端 TLS 被中间设备复位（同一时刻 curl 可通）时不成立。现规定：只对**确定无副作用**的失败（连不上／被复位／超时）指数退避重试，收到任何 HTTP 响应即绝不重试；仍不通则改走系统 `curl`；失败消息 MUST 明说"未投递任何记录，可安全重跑"——这句话的工程含义是幂等（投递按 id upsert、同字节重投不产生第二条），不是安慰。④ **测试数据的判定 MUST 可机读复现**：§10 不许索引悄悄少发内容，那么"`exclude_test` 到底排除了什么"就更不能靠 handle 命名习惯隐式生效。判据分三层（归属 handle 标记 / 声明自身标记 / 索引逐条登记），第三层存在的理由是 append-only 下已签名字节改不了——索引只能**登记并公开理由**，不能改写、也不能假装没看见。**元教训**：这一轮的两处假通路（`curl` 逃生舱忘了带 `--data-binary` → 实际发出空请求体；连不上时 `%{http_code}` 返回 000 被当合法响应码继续下传，报成"预检响应不可解析"）都是**部署前的工具闸**抓的。只测"能不能连通"永远碰不到它们；错误口径必须像字节契约一样被断言。

19. **同一条判据必须覆盖所有写入口，否则"权利"只在其中一条路上存在（2026-10-17，采用者用真钥匙实测撤回被拒后定案）**：§5.4 细则第 5 条（2026-10-12）裁定"纯撤回是状态转换，不是修订"，判据为**剔除 `withdrawn` 与 `updated_at` 后与首见副本逐字一致**。但该条措辞是"在源上为记录追加 `withdrawn: true`"，参考实现据此只把豁免装在**爬取侧**。自托管源改得了自己的文件，于是它工作；**托管源的声明者碰不到源文件，唯一写入口是投递端点**——同一条规范下就出现"一边能撤、一边把撤回判成 `immutable_conflict`"。撤回是四态生命周期的收口：做不到撤回，"地址属于自己、内容由自己掌控"只剩半句。**裁定**：① 该判据 MUST 被所有写入口共用同一实现（本参考实现抽出单一函数），投递端点接受同 id 的纯撤回、只翻转状态，内容字节仍保留首见副本；② 托管清单 MUST 把该 id 对外服务的字节变为带 `withdrawn: true` 的那条，使任何爬取方重抓都收敛到"已撤回"，不会被冲回已发布；③ 撤回为**终态**，不得靠重投原字节逆转（`withdrawn_terminal`），重新表达请发新 id；④ 默认口径 MUST 不返回已撤回记录（`include_withdrawn` 显式取回），但对账入口不受此限：字节入口永远返回首见副本并附状态头，人可读地址 MUST 呈现为**看得见的墓碑**（§21 第 4 条要求"明示撤回且保留可核对的原文地址"）；若保留 410 作为默认，其回执 MUST 给出取回墓碑与核对字节的精确入口，不得是死路；⑤ 预检 MUST 当场告知本次投递将作为撤回生效。**元教训**：规范用"在源上……"这类**只对某一种托管拓扑成立**的措辞表述义务时，必须同时给出该义务在其它拓扑下的等价形式；判据写在规范里 ≠ 判据在每个入口都生效，而踩出来的人只会是采用者。

20. **可回收的最小授权：委托子钥与"时间不追溯"（2026-10-17，采用者把真钥匙交给第三方 Agent 之后定案）**：§6.4-11 把"交付即全额授权"写成了规则，也就把风险写成了规则——Agent 拿到的 anchor 私钥同时能发布、换根、关闭、迁移，而"收回授权"只有换根一条路（连带影响历史复核）。本条给出协议内的最小授权：**anchor 签发、可吊销、权限受限的工作钥**。口径五条：① **委托凭证本身是一份 anchor 签名对象**（`type: "odp-key-delegation"`，含 `handle`、`ts`、`delegate{key_id,alg,value}`、`granted`、`not_before/not_after`），签名字节沿用 §12 约定——剔除 `signature` 后整对象的 JCS 规范化字节直签 Ed25519；宿主文档 `public_keys[]` 的子钥条目 MUST 内嵌**完整凭证**，使任何第三方可离线复算委托链，不依赖索引私有状态（§7 可 fork 性）。② **权限闭集且 fail-closed**：本期只承认 `publish`、`withdraw`；出现未定义值整条拒收，出现 `rotate_anchor`/`close`/`migrate`/`manage_keys` 直接拒绝——索引没有实现的权限，不允许被写进凭证，否则产生"凭证说有、实现当没有"的静默降级。③ **吊销必须真能吊销**：旧凭证的 anchor 签名永不过期，因此被吊销的 `key_id` **永久占位**，续期必须换新 key_id，且新授权的时间戳 MUST 严格单调新于既有记录（否则重放旧报文即可复活子钥，吊销是假的）。④ **时间语义不得追溯**：有效期与吊销只约束**写入口**；读侧复核只看签名与链。若把它作用于复核，索引每次复爬都会把有效期内合法发布的存量声明判成不可用——那与 §6.4-7、§6.4-15 同族，是一个会自我追溯的口径。⑤ **归因必须可见**：读侧 MUST 输出 `signed_by`（`anchor` 或 `delegate:<key_id>`），否则子钥泄露期间的乱发会被算到声明者头上，而"谁说的"恰恰是 §10 中立性要保护的东西。身份态规则不变：域名一致 + 链上任意有效钥签名仍为 `verified_signed`——委托只影响"是否放行"，不改变"身份归属谁"。**元教训**：给"人把钥匙交出去"这件事设计协议时，可回收性与可归因性不是附加功能；缺了它们，规则只是在为一个危险做法背书。多级委托与 MCP 发布通道均不在本期。

## 7. 检索契约（Retrieval Contract）

所有索引节点必须暴露以下 HTTP 接口（`Accept: application/json`）：

```
GET /api/v1/declarations
    ?cursor=<opaque>            # 游标分页
    &updated_since=<RFC3339>    # 增量同步
    &type=idea|capability|intent|notice
    &tag=<tag>
    &q=<关键词>                 # 匹配 title/summary/claims，不排名、只过滤
    &responds_to=<id>           # 取指向某声明的全部回应（声明间对话图入口）
    &include_withdrawn=false
→ 200 {"items": [Declaration…], "next_cursor": "…", "total_estimate": N}

GET /api/v1/declarations/{id}
→ 200 Declaration | 404 {"error":"not_found"} | 410 {"error":"withdrawn","tombstone":…}

GET /api/v1/stats
→ 200 {"sources": N, "declarations": N, "types": {…}, "last_sync": "…", "crawl_observations": {…}}
```

**错误响应自带引导**：所有非 2xx 响应必须让投递 Agent 从错误本身得知下一步，无需另读文档——401 附注册/密钥指引、422 附字段级说明与全部合法枚举、403 配额类错误附所需与现有差额、404 附缺失 id 列表。此模式源自供需情报库与 Agent 问答板的实战（next_action / hint 设计），是本协议 API 的规范性行为。

**一致性要求**：同一声明在任何符合契约的索引中的**JCS 规范化哈希必须一致**（§12），且索引回传的是源的原始字节（§6.2，禁止重新序列化）；各索引的 `id` 全局可解析。任何索引宕机，消费方可凭 `id` 直接回访 `source_uri`。检索响应必须携带 `source_status`（§5.4 生命周期状态）。`updated_since` 增量同步以 `updated_at` 为准。

**对消费 Agent 的行为规范（写入 llms.txt，见 §9）**：

- 必须引用 `source_uri` 作为出处；
- 转述 `claims` 时保留 `kind` 与 `confidence`，禁止把 `prediction` 当事实转述；
- `intent` 类声明包含联系意向，消费方代表用户回联时应表明 Agent 身份。

## 8. 与现有生态的映射

| 生态 | ODP 的接入方式 |
|---|---|
| MCP | 索引提供 MCP Server，暴露工具 `search_declarations(filters)`、`get_declaration(id)`、`submit_source(source_uri)`，使 ODP 原生出现在 MCP 兼容 Agent 的工具列表中 |
| llms.txt | 索引根目录提供 `llms.txt`（见 §9），使通用 AI 搜索引擎能理解并引用本协议与全量声明。**必答题："那 ODP 相对 llms.txt 的增量是什么？"** —— llms.txt 是**站点级的一份自述指针**：静态、无类型、无身份、无生命周期，告诉爬虫"这个站有什么"；ODP 提供的是**载荷本身**的五项增量：(a) **逐条评估级语义**（`kind`/`confidence`/`falsifiable_by`，让引擎能判断"这条主张在什么证据前失效"）；(b) **身份绑定**（anchor 密钥 + 域名回指，引用可追到第一方）；(c) **生命周期**（`valid_until`/`updated_at`/四态 + append-only，回答"此刻是否仍然成立"——llms.txt 无此概念）；(d) **跨源回应图**（`responds_to`，主张之间可形成可追溯的对话）；(e) **可复算的中立检索契约**（§10，任何人可 fork 索引）。关系是**包装与载荷**：llms.txt 是 ODP 的四路机器入口之一，不是它的替代品 |
| ARD（Agentic Resource Discovery） | **能力发现让位给 ARD，ODP 做互操作而非竞争**：工具/技能/agent 的可调用性描述与调用契约以 ARD（`ai-catalog.json`）为准；ODP 的 `capability` 类型声明只承载一个 `ard_catalog` 指针，把"我能做什么、怎么调用"完整交给声明者站点的 ARD 目录。ODP 的自有领地是 ARD 不覆盖的部分——**人的公开表达**：想法、意向、面向 Agent 的公告 |
| Schema.org | **互补而非竞争**：Schema.org 标注 HTML 页面内容（Person/Offer/JobPosting），帮 AI 理解"页面说了什么"；ODP 承载独立于页面的第一方声明，带评估级语义（kind/confidence/falsifiable_by）与不可变生命周期，让 AI 直接引用"谁主张了什么、何时可被推翻"。证据页用 Schema.org，主张本身用 ODP |
| 通用爬虫 | 声明清单同时以 HTML 索引页镜像（人可看、爬虫可抓），robots.txt 显式允许 GPTBot、ClaudeBot、PerplexityBot、Google-Extended 等 |
| RSS/Atom | 提供 `odp.rss` 镜像，供现有聚合器零成本转引 |

## 9. findable.cn 参考实现规范

可见（Findable）= ODP 的第一个全功能索引节点，其形态由本协议约束，**不享有任何超出协议的特殊地位**。

**地址政策（draft-15 记录）**：规范与运行实例的**稳定地址**一律使用 `ade.pub`（`findable.cn` 备案完成前的承载域，备案后归位）；任何发布平台的预览域名（含各类临时 host）**不得写入规范或机器文档**，仅可作镜像。2026-10-12 曾发生预览域名随发布轮换导致同一规范出现两个地址的事件，本政策即为防止复发而立。

**名称与域名**

- 中文名"可见"，取自本协议的使命：让表达在被算法分配可见性的时代重新变得可见；
- 域名 `findable.cn`（可被找到的）。

**必须提供**

1. §6.2 与 §7 定义的全部接口（含 `POST /api/v1/sources` 推送登记、MCP Server 端点）；
2. 根目录 `llms.txt`：向 AI 引擎自述"本站是 ODP 开放声明协议的索引节点，全部内容为机器可读声明，检索接口见 /api/v1/declarations"；
3. 本站自身的宿主文档 `https://findable.cn/.well-known/odp-host.json`——**可见的第一个声明者必须是可见自己**：用它发布协议版本变更、收录策略与运行状态通告（`notice` 类型），以身作则遵守全部约束；
4. 全量数据的开放下载：`GET /api/v1/dump`（NDJSON 快照，日更）——保证任何第三方随时可以 fork 出完整的平行索引；
5. 托管源服务（§6.3）：`findable.cn/@<handle>`，供无域名者经其 Agent 零摩擦发布，含免费全量导出与 §17 迁移支持——**托管是入口，不是笼子**。

**明确不做**

无审核队列、无排序、无推荐、无广告位、无"精选"。检索与源登记不设账号墙（协议路径无需注册）；托管源需要账号以持有 handle，但导出与迁移永远免费（§6.3）。

**运行与存续承诺（写进首页）**

- 托管于声明者自有云服务器；若主运行人停止维护：(a) 全部数据转储保持公开可下载，(b) 域名与运行文档移交给首位表明意愿的 fork 方，或 (c) 挂出 `notice` 公告退役日期；三者必居其一，公告即生效。

## 10. 索引行为约束（可审计的匹配）

这是本协议的规范性核心，不是建议。draft-03 起对本节做了关键澄清：**该禁的不是排序，是不可复现、不可问责的排序。** 检索的本质就是排序——只准按时间排，等于把匹配能力阉割掉，索引退化成单纯聚合器。因此本节把边界画在"可复现性"上：

**禁止（索引层）**

1. 基于用户画像、行为历史、设备、地理位置的**个性化排序或差异化可见性**；
2. 基于付费关系、利益交换的**加权**——收费改变可见顺序即为违规；
3. 基于热度、互动量、点击率的**参与度排序**（这正是本协议要逃离的旧世界）；
4. 自创"热门 / 精选 / 编辑推荐"等**影响默认可见性的策展分区**；
5. 以内容语义为由拒收、隐藏或降权已收录声明（§12 下架规则除外）。

**允许，且必须可审计（索引层）**

6. **基于查询的相关性排序**（BM25、向量相似度等）：允许，条件是——(a) 仅作为显式查询参数（如 `sort=relevance`）提供，**默认排序恒为确定性字段序**（`published_at` 倒序 / `id` 字典序）；(b) 所用算法、模型及其版本在站点文档中**公开声明**，同输入必同输出；(c) 排序函数变更视同协议实现变更，须公告。换 embedding 模型导致结果漂移是允许的，前提是版本被记录、行为可复现、事后可审计；
7. **客观准入约束**（§6.2 容量治理：速率、配额、字节上限）：作用于收录之前、与内容无关，不属于可见性干预。

**一句话**：索引可以聪明，但必须把"我怎么排的"写在明处、钉死版本、接受复算。任何想让结果"悄悄偏向谁"的排序——无论偏向付费方、老用户还是索引自己的偏好——都是违规。违规的索引不再是合规 ODP 索引，消费方应依据 `source_uri` 绕开它。

`signed` 标注（§17.5）与任何置信度信息只可作为**过滤参数**，永不作为排序权重。

## 11. 版本与兼容

- 文档中所有实现必须忽略未知字段；
- 字段的语义变更需递增 `odp_version` 主版本；新增可选字段仅需递增次版本并在协议仓库登记；
- 协议文档的每次修订以 `notice` 类型声明发布在 findable.cn 与各镜像，讨论公开进行。

## 12. 法律边界与签名扩展

**下架规则（索引唯一允许的过滤）**：仅响应权利人或主管机关对具体声明的合法下架要求；执行时索引发布 `notice` 说明依据与范围，源上的内容不受索引影响依然存在。这保证"删除"永远是索引层的局部行为，而不是协议层的中央权力。

**签名规范**：对**除 `signature` 字段外的整条声明**做 RFC 8785（JCS）JSON 规范化，**直接对规范化字节做 Ed25519 签名**——Ed25519 内部已含散列，**不得**先做 SHA-256 等预散列；预散列签名的验证必然失败（真实事故记录见 §6.4 第 7 条）。不得采用"部分字段签名"——任何不被覆盖的字段（`title`、`summary`、`type`、`source_uri`、`translations` 等）都视为可被无痕篡改。公钥登记于宿主文档；其中 `anchor_key_id` 指向的公钥兼任身份锚（跨域名延续身份的依据，见 §17）。签名状态作为检索过滤参数（`signed=true`），**永不作为排序权重**——与 §10 一致。

### 12.1 哈希定义与测试向量（2026-10-16 补，回应采用者实测发现 1；同时清偿 §6.4-7 欠下的"测试向量"债）

**规范文本**：一条记录的 `index_canonical_hash` / `canonical_hash` 定义为

```
SHA-256( canonical_json( 记录 minus "signature" 字段 ) )      # RFC 8785 规范化字节，再取散列
```

三点必须写明，否则独立实现必然对账失败：① **剔除 `signature`**——签名本身覆盖的就是去掉签名字段的记录，若把它算进哈希，哈希会随每次签名 while 内容不变而漂移；② 散列对象是**规范化字节**而非源字节（源字节常含缩进差异，见 §6.2）；③ 记录**无法解析为 JSON** 时，索引退化为 `SHA-256(源字节)` 并必须在响应里如实标注该情形，不得与规范化哈希混为一谈。

**测试向量（可直接跑；本向量只做验签侧，签名私钥为一次性生成、随进程丢弃，规范不发布任何私钥）**

待签记录（JSON，键序与空白**无关**，任何实现先规范化即可）：

```json
{"odp_version":"1.0","id":"urn:odp:example.org:2026:notice-vector","type":"notice","lang":"zh-CN","title":"ODP §12 测试向量","summary":"含非 ASCII、浮点、null、布尔、嵌套 claims 的最小记录。","claims":[{"text":"向量断言：中文与 é，数字 0.65 / 1 / -0.0","kind":"observation","confidence":0.65,"falsifiable_by":"任何与本向量不一致的实现输出"},{"text":"第二条：布尔与空值","kind":"value","confidence":1}],"tags":["test-vector","odp"],"audience":"both","contact":"mailto:vector@example.org","source_uri":"https://example.org/odp/vector.ndjson","published_at":"2026-10-16T00:00:00Z","updated_at":"2026-10-16T00:00:00Z","valid_until":null,"supersedes":null,"responds_to":[]}
```

期望输出（三者缺一即实现不合规）：

| 项 | 值 |
|---|---|
| 规范化字节长度 | `726` |
| 规范化字节（base64） | `eyJhdWRpZW5jZSI6ImJvdGgiLCJjbGFpbXMiOlt7ImNvbmZpZGVuY2UiOjAuNjUsImZhbHNpZmlhYmxlX2J5Ijoi5Lu75L2V5LiO5pys5ZCR6YeP5LiN5LiA6Ie055qE5a6e546w6L6T5Ye6Iiwia2luZCI6Im9ic2VydmF0aW9uIiwidGV4dCI6IuWQkemHj+aWreiogO+8muS4reaWh+S4jiDDqe+8jOaVsOWtlyAwLjY1IC8gMSAvIC0wLjAifSx7ImNvbmZpZGVuY2UiOjEsImtpbmQiOiJ2YWx1ZSIsInRleHQiOiLnrKzkuozmnaHvvJrluIPlsJTkuI7nqbrlgLwifV0sImNvbnRhY3QiOiJtYWlsdG86dmVjdG9yQGV4YW1wbGUub3JnIiwiaWQiOiJ1cm46b2RwOmV4YW1wbGUub3JnOjIwMjY6bm90aWNlLXZlY3RvciIsImxhbmciOiJ6aC1DTiIsIm9kcF92ZXJzaW9uIjoiMS4wIiwicHVibGlzaGVkX2F0IjoiMjAyNi0xMC0xNlQwMDowMDowMFoiLCJyZXNwb25kc190byI6W10sInNvdXJjZV91cmkiOiJodHRwczovL2V4YW1wbGUub3JnL29kcC92ZWN0b3IubmRqc29uIiwic3VtbWFyeSI6IuWQq+mdniBBU0NJSeOAgea1rueCueOAgW51bGzjgIHluIPlsJTjgIHltYzlpZcgY2xhaW1zIOeahOacgOWwj+iusOW9leOAgiIsInN1cGVyc2VkZXMiOm51bGwsInRhZ3MiOlsidGVzdC12ZWN0b3IiLCJvZHAiXSwidGl0bGUiOiJPRFAgwqcxMiDmtYvor5XlkJHph48iLCJ0eXBlIjoibm90aWNlIiwidXBkYXRlZF9hdCI6IjIwMjYtMTAtMTZUMDA6MDA6MDBaIiwidmFsaWRfdW50aWwiOm51bGx9` |
| 该记录的哈希（= `canonical_hash`） | `432a46086194b07c1f1da3d4df1d34bafc4e2fcbfa7b35d83fec4b72301ae989` |
| 公钥（base64 raw32） | `uUPC5syLwxvwpSKGHe+78i1B+rsnSvmLfyhocDbH2aw=` |
| 签名（base64，Ed25519 直签上述规范化字节） | `qOX/VL8ICOUHdXjYl1mVgtNo4yt9v4FPg8vZeJ4fP1t11w5oocF+AQHlzV+C4yBz829sKcEVIJBUuWaL9jaNCw==` |

覆盖点：非 ASCII 与重音字符、浮点 `0.65`、整数 `1`、`null` 值、空数组、布尔性字段与多层嵌套——规范化最容易出分歧的地方。任何实现只要能用上表公钥验通该签名、并复现同一哈希，即与参考实现在 §12 上互通。
（附带一条反向断言，防"验签形同虚设"：把上述任一字节改掉，验签 MUST 失败。）

**同源签名的信任边界（采纳 ARD 社区教训）**：签名与被签内容同置一个域名时，签名只证明**完整性**（文件未被传输篡改），不证明**身份可信**——控制域名的人同时控制密钥发布位置。因此 anchor 私钥必须保存在域名之外（声明者本地/硬件），公钥一经登记不得由后续的同域名操作替换（替换 = §17.4 的轮换流程，需旧钥签名）。签名在 ODP 中的正当用途有二：完整性校验 + 跨域名身份延续；它不构成对声明者信誉的背书。

**防滥用（v1.x 扩展点）**：速率限制、内容大小上限（单声明 ≤ 256KB）、`intent` 回联的 Agent 身份标识握手。

## 13. 安全考量

- **域名仿冒**：`id` 中的 `<host>` 与 `source_uri` 域名强制一致，检索方必须双项核对；身份本体以 anchor 公钥为准（§17），域名只是解析位置；
- **垃圾灌入与 DoS**：v1 即实施 §6.2 容量治理（速率、配额、字节上限）——这是客观准入约束，与 §10 中立性不冲突；无密钥源适用最低配额，签名源可凭 §12 验证获得更高配额。**判断"内容值不值得存在"不是索引的职责**，语义层面的过滤交给消费方（`signed=true`、`confidence` 阈值、各自的相关性实现）；
- **同源签名信任陷阱**：见 §12——签名证明完整性而非身份；anchor 私钥必须域外保存；
- **内容风险**：见 §12 下架规则，责任层级清晰——违法内容的处置对象是具体声明，而非全网降权；
- **单点风险**：由拉取模型 + 全量转储 + fork 义务（§9）消解。

## 14. 路线图

- **v1.0-draft-15**（当前）：按第五轮评审收口三处过度断言与一处硬矛盾——① **首页里程碑条款曾把"爬虫抓取"写进判据、并以 M2 口径作冻结触发**（与 §1.1 相反：等于把自己宣布不可能达成的条件当死刑开关），已改为 M1 口径，且**首页不再复述判据、只指向 §1.1**（第三轮首页漂移，故改结构而非改文字）；② **P7 由经验结论降为战略选择**：tpool 的 106 用户按本方案自订标准属近乎零分发，"点火后仍零成交"无据，一个从未达到流动性的池子不能证伪需求；③ **新增 E3 承重实验**（A 普通HTML / B ODP / C HTML+Schema.org 三组对照，附功效约束：三组皆零只能判"样本不足"不得判"假设证伪"），E1/E2 降为辅助——承重假设此前无任何实验检验；④ §15 冷启动第二里程碑（M2 口径）改为长期观察项；intent 门槛删除无合法判定主体的"双方确认成交"，只留索引可自证的密度；⑤ §2 G4 与 §10 对齐为"可审计的匹配"；§20 明确 51buy/51sell 属**未上线的设计资产**；⑥ 新增 §1.1 **分层定位**与 §8 **ODP 相对 llms.txt 的增量**——MVP 层的真实对手是 GEO / llms.txt 生态，不是 ARD/MCP；
- **v1.0-draft-14**：两项裁定收口——① §16"不设隐私中继"经 tpool 反证复核后**维持**，并完整记录权衡理由与替代救济（声明者使用可撤销别名地址），未来若有多索引共识可作为独立垂直 profile 另提；② §15 新增**索引 MVP 实现蓝本**（FastAPI+nginx+MySQL 形态、openapi/mcp/server-card/llms.txt 四入口、分档配额、错误自带引导），继承 tpool 已验证的工程形态，同时明确排除转接与加密落库不进索引核心；tpool 本身保持原样不改造；
- **v1.0-draft-13**：E0 收口——对唯一仍在运营的同类平台 tpool.com.cn 做服务器只读取证，实测 106 用户 / 63 Agent / **联系请求·面试·投递·订单全部为 0** / 企业侧全空 / 用户增长自 2026-07-04 起归零；首页"60万+"经核实为抓取内容表（643,450 行）而非用户。据此新增 **§4 设计原则 P7（无对手方依赖）**：协议价值不得押在"招募交易对手方"上，intent 保留为声明类型但 **findable 不运营意向撮合**；同时**撤销 draft-12 的"定时驱动配方解决 intent 冷启动"论断**（MCP 长期有人调用而成交仍为零——自驱动无法创造缺席的第二方），该机制降级为声明者自查 contact 的便利功能；〔本条中"P7 协议价值不得押在招募交易对手方"的表述方式已被 draft-15 修订：改为战略选择，不再作为经验结论；"自驱动无法创造缺席的第二方"一并保留为观察，但不足以推出需求不存在〕
- **v1.0-draft-12**：E0 行为实验回收（§15）——四平台死因澄清（51buy/51sell 从未正式上线、aiseek/ADE 死于零推广=分发失败非需求失败），"需求死亡"威胁撤销但 intent 仍未被真实检验；确立 §4 设计原则 **P6 人类驱动假设**（Agent 无自主性，每次互动背后必有一次人类驱动）；据此重写 §1.1 M2（从"等 Agent 自主"转为"依附 M1 GEO 复利、盯人类驱动调用的滞后曲线"）。〔本条原附"定时驱动解决 intent 冷启动"论断已被 draft-13 撤销〕
- **v1.0-draft-11**：吸收"四平台已下线"事实的行为证据——§20.7 从"旗舰源存在"修正为"机制保留、实例清零、下线列为未决不利证据"；§15 新增 **E0 行为实验**（后于 draft-12 回收为已澄清事实）；§6.2 PII 从"整条拒收"改为**字段级遮蔽 + 申诉通道 + 声明者 business 覆写**（消除对合法商业公告的误伤，见 §20.7 复盘教训）；
- **v1.0-draft-10**：声明间回应原语 `responds_to` 转正（§5.3：回应即声明、存回应者自己的源、不作排序权重；对话图去中心化）；检索契约新增 `responds_to` 过滤参数与"错误响应自带引导"规范（§7）；§2 非目标精确化（平台内社交不做，声明间回应是内容引用）。资产出处：aiseek 问答板与 ADE 数据交换的互动机制映射——平台层互动（积分/巡查/黑名单）不进协议，问答线程可映射为 responds_to 声明链；
- **v1.0-draft-09**：M1 判定收紧为"公开输出引用 source_uri"唯一判据，爬虫抓取降级为只公示的观察指标（防止自我安慰）；新增 Schema.org 差异化预答（§1.1/§8：Schema.org 帮 AI 理解页面，ODP 让 AI 直接引用主张）；51buy/51sell 扶正为 classifieds 旗舰源（§20.7：平台负责体验与质量，ODP 负责开放分发）；
- **v1.0-draft-08**：分类三层定案——协议核心不设分类树、tags 轻分类、垂直 profile 承载重分类（§15 机制 + §5.3 `profile` 字段）；PII 硬闸入协议核心（§6.2，源自 51buy 实战：手机号/身份证 GB11643/银行卡 Luhn 语法级拒收）；第一个垂直包 classifieds（§20：12 形态 × 14 行业 × 字段白名单 × 预算单位映射，买卖镜像对齐，资产继承自 51buy/51sell 供需情报库）；
- **v1.0-draft-07**：托管源强制绑定 anchor 密钥（Agent 生成、私钥不出声明者侧）并把"升学"明确定义为 §17 迁移特例（§6.3）；"管道与房东"矛盾显式化解（§6.3）；§1.1 里程碑拆分 M1（12 个月，被 AI 搜索引用，唯一进承诺）/ M2（被 Agent 自主检索，愿景不进承诺）；补校正"单条即有价值"的隐含读者是人、MVP 真实消费形态是 AI 搜索回答（§1.1）；§15 新增初探两种解释与 E1/E2 区分实验；
- **v1.0-draft-06**：§1.1 新增启动序列（MVP 以 idea/notice/experience 起步，intent 降为第二阶段愿景）与"被引用是生存"条款（不承诺可见性、只承诺可引用性；多路检索对冲单一引擎依赖）；§15 intent 流动性条款加入启动序列；
- **v1.0-draft-05**：死刑条款改为分级里程碑承诺与可观测判定口径（§1.1）；补强"可机器评估"价值论证（§1.1）；§15 新增 intent 垂直流动性条款。另定：findable.cn 正式解析时，按 §17 完成预览域名→正式域名的签名迁移（odp-moved.json + anchor 密钥），作为协议第一次 dogfooding 演示；
- **v1.0-draft-04**：托管源与升学通道（§6.3）——吸收 GitHub 教训：平台托管是大众化前提，个人主页式自托管要求会复刻摩擦死法；claims 新增 `experience` 类型；G1 与 §9"无注册"承诺相应修订；
- **v1.0-draft-03**：吸收外部评审——可审计匹配（§10）、append-only 修订模型与生命周期状态（§5.4）、全记录 JCS 签名（§12）、容量治理入 v1（§6.2/§13）、消费侧商业化边界（§2）、capability 让位 ARD（§5.3/§8）；
- **v1.0**：三个独立索引节点互联（哪怕都是个人 VPS），签名验证发布；ARD 互操作指针实测；
- **v1.x**：intent 回联握手规范。（原"claim 机器互评"已随 `responds_to` 字段转入 v1.0 正式规范，见 §5.3/§7。）

## 15. MVP 验收（工程口径）

findable.cn 第一版应做到：

1. 静态首页 + 协议全文（HTML 与 Markdown 双版本）+ `llms.txt`；
2. 实现 §7 全部 GET 接口 + `POST /api/v1/sources`；
3. 小时级源爬取 + 墓碑/三态同步 + 日更全量转储 + §6.2 容量治理（速率/配额/字节上限）；
4. MCP Server 暴露 3 个工具；
5. 可见自身的 `/.well-known/odp-host.json` 与至少 3 条示范声明（`idea`：本协议本身；`intent`：征集首批声明源；`notice`：运行状态）；
6. 托管源最小版（§6.3）：`/@<handle>` 地址 + Agent 可经 API 写入声明 + 一键全量导出；
7. 全部代码 MIT 开源，README 第一节即本规范链接。
8. **G6 的验收判据（可 curl，不许口头声称）**：① 托管源声明者发布后，其 `/@<handle>` 返回 `text/html` 且姓名与 claims 出现在**响应字节**里（不执行 JS 也读得到）；② `human_uri` 或内容协商二者至少其一存在——验证式：`curl -H 'Accept: text/html' /d/<id>` 返回 HTML **且** `/raw/<id>` 返回同一批字节与同一 `X-ODP-Canonical-Hash`；③ 机器清单响应带 `Link: rel="alternate"; type="text/html"`；④ 发布动作的**回执里含人可读地址**（发布页成功卡片或 Agent 回报文本）——四项任一不过，MVP 判定不通过。

**冷启动标准**：不是注册数。里程碑 = 出现 10 个非声明者本人运营的独立源，且其中至少 3 条声明被 E3 检出非零引用。**长期观察项（非门槛，v1.0-draft-15 改）**：第三方 Agent 产品在无人工干预下检索并引用 ODP 声明——此项属 M2，P6 已判定当前条件下不会自发发生、§1.1 已定为不设期限，故**不得作为任何启动或冻结的门槛**，只作趋势观测记录。

**intent 流动性条款（v1.0-draft-15 修订：门槛必须协议方可自观测）**：`idea`/`notice`/`capability` 单条即有用，唯 `intent` 必须有流动性才有用——只有 10 条意向的通用意向索引价值为零。**启动序列**：MVP 冷启动以 idea/notice/experience 起步（单向表达、无需供给密度，见 §1.1 启动序列），intent 为第二阶段。intent 冷启动**必须垂直化**，激活门槛为**单一垂直领域内的密度**：同领域、同库 intent 供需两侧各 ≥ 20 条——**这是索引自己数得出来的唯一判据**。

原"发生至少一次经 `contact` 回联达成的实际匹配并获双方确认"已从门槛中**删除**：匹配成交事件只有撮合运营方能观测，而 P7 判定 findable 不运营撮合，若把它留在门槛里，等于设一扇**无合法判定主体的门**（永远点不亮，也永远证明不了不亮）。成交信息改为：**第三方可自愿上报**，索引如实记录上报及其来源，不核实、不背书、**不作为 findable 的义务**，也不参与任何排序（§10）。垂直领域由首批声明者与索引运营方共同选定；达成密度门槛之前，不向通用方向扩张。

**E0 补充：tpool（在运营的真实案例，2026-10-11 服务器实测取证）**：tpool.com.cn 是声明者实际运营、仍在线的同类平台——面向 Agent 的招聘数据服务，已实现 OpenAPI + MCP + server-card + llms.txt + 按 Agent 每日配额 + 简历池零联系方式转接（落库加密、手机号掩码、每日 5 封上限）。实测数据（读库聚合计数，未取任何个人数据）：

| 指标 | 实测值 |
|---|---|
| 注册用户 / Agent / 简历 | 106 / 63 / 108 |
| 用户注册跨度 | 2026-05-24 → **2026-07-04 后归零**（3 个月无新增） |
| **联系请求 / 面试 / 投递 / 订单** | **0 / 0 / 0 / 0** |
| 企业侧（Agent·档案·岗位） | **0 / 0 / 0** |
| 首页标称"60万+"的真实构成 | `internships` 抓取表 643,450 行（内容，非用户） |
| 保留日志内 API/MCP 外部调用 | 约 120 次/10 天，集中于少数固定 IP（含扫描器噪声） |

**E0 最终结论（按证据强度分级）**：

- **被验证可行的（强证据）**：供给与隐私机制——零联系方式转接、落库加密、分档配额、面向 Agent 的 OpenAPI/MCP/server-card 在真实站点上跑通并持续运行；P6（人类驱动假设）为直接观测所得。
- **未被证明也未被证伪的（弱证据，不可用于结论）**：双边意向匹配的需求是否存在。tpool 仅 106 注册用户、增长止于 2026-07-04，按本条对 aiseek/ADE 适用的同一标准即**近乎零分发**——一个从未达到最小流动性的池子，其零成交不构成对需求的任何检验。**不得把"点火后仍零成交"当作论据，因为它没有真的点着火。**
- 因此 **P7 是战略选择（对我方能力边界的判断），不是经验结论（对市场需求的判断）**，详见 §4 P7。

**E3（承重实验，优先级高于 E1/E2；v1.0-draft-15 新增）**：draft-14 之后全部价值主张收敛为一句话——**评估级语义（`kind`/`confidence`/`falsifiable_by`/`valid_until`/`source_uri`）能提高被 AI 引用的概率**。若此句不成立，ODP 退化为"带 schema 的 llms.txt"，M1 没有理由发生。**E1/E2 检验的是供给侧存在性，测不到这句话；E2 的"等待收录"更是绕过了它**（爬取是两种形态共有的前提，不构成差异）。故必须单测：

| 项 | 设计 |
|---|---|
| 分组 | 同一正文文字，三种发布形态：**(A)** 普通 HTML（无任何结构化标注）；**(B)** ODP 声明（完整评估级语义）；**(C)** HTML + Schema.org 标注（**对照组必须包含它**——它是 §1.1 预答里"每个技术读者第一个会问的"最强替代方案，缺了 C 组就无法区分"ODP 有效"与"任何机器可读标注都有效"） |
| 语料 | 20–30 条真实主张，A/B/C 各占三分之一，同域名不同路径，发布时间与外链条件对齐 |
| 选题约束 | 必须是**已有真实搜索需求**的问题（先用各引擎跑一遍，确认当前回答来自第三方页面而非空白），否则引用率地板为 0，测不出差异 |
| 测量 | 2–6 周后用**预先固定的问题集**逐引擎提问（ChatGPT / Perplexity / Google AI Overviews / 豆包 / Kimi 等），记录回答是否引用 A/B/C 组 URL |
| 判定 | **B > A 且 B ≥ C** → 承重假设成立，M1 有理由；**B ≈ A** → 结构化不是差异点，差异化必须改押多路检索 / 可验证签名 / 可 fork 索引，或诚实承认 ODP 是 llms.txt 的加强版；**C > B** → 直接采用 Schema.org 路线，ODP 收缩为它的投递层 |
| **功效约束（关键）** | 预先登记"三组引用率均为 0"的解读为**样本量不足或分发不够，不是假设被证伪**——零对小规模语料是常态，不得当作结论。只有出现非零引用且组间有差异时，才作判定 |
| 附带产出 | 得到真实**基线引用率**，用于校准 M1 的 12 个月目标是否现实（当前该目标值尚无基线支撑） |

**E1/E2 降级为辅助实验**：它们回答"开放网上有没有意向内容"，对 M1 是背景信息而非检验。E3 是唯一能给出"继续 / 转向"信号的实验。

**由 P7 推出的取舍（注意其性质是选择，不是预测）**：M1 之所以是唯一进承诺的赌注，不是因为"双边需求不存在"，而是因为它的消费方是无限、无偏的搜索引擎，**不要求我方具备招募能力**；而任何需要同时招到供需两边的功能，都把我方放进四次尝试中从未做成过的那类位置。故 intent 作为**声明类型**保留（人有权公开表达意向），**findable 自身不运营意向撮合市场**——那是第三方应用在此格式之上、自负成败的事。

**索引 MVP 的实现蓝本（v1.0-draft-14 新增；tpool 本身保持原样、不改造）**：tpool 已在同等量级服务器上验证过一套可运行的 Agent 面向基础设施，索引 MVP 直接沿用其技术形态而非重新发明——

1. **技术栈**：FastAPI + uvicorn（回环端口）+ nginx 反代 + MySQL，systemd 托管并设 `MemoryHigh/MemoryMax`——3.6G 内存的单台小服务器即够；
2. **三重机器入口**：`openapi.json` + `/mcp` 服务 + `/.well-known/mcp/server-card.json`，加 `llms.txt`（§9）共同构成 §8 的互操作面；其中 MCP 与 server-card 是已被真实客户端走通的路径，不是纸面设计；
3. **配额分档**：按操作类型分设每日上限（而非一刀切），并把限频策略写进自述端点供投递 Agent 接入前读取；错误响应自带引导（§7）+ 429 指数退避建议；
4. **登记与指纹**：需要写索引时注册即发 key、库中只存哈希——注意与 ODP 核心的差别：**发布声明本身永远无需注册**（§6.1/§6.3），登记只服务于推送登记这类可选加速路径；
5. **明确不继承**：联系方式转接与简历落库加密**不进索引核心**（§16 已复核维持不设中继）；索引只做 §6.2 字段级 PII 遮蔽，且遮蔽仅作用于索引副本。

**垂直 profile 机制**：重分类不进协议核心，进**垂直 profile**——由生态定义、版本化、经注册表公开 schema 的结构化扩展包。声明用可选 `profile` 字段引用（如 `vp-classifieds/0.1`），按 profile 的字段白名单携带结构化需求；索引公开全部已注册 profile 的 schema，供投递 Agent 对号入座（此机制曾在 51buy/51sell 供需情报库实现——公开 /meta 架构、Agent 自动组装结构化需求；项目现已下线，其下线证据见 §15 E0，但 /meta 式"公开架构供 Agent 对号入座"的实现模式本身经运行验证有效）。profile 遵循"只增不删"的演进策略；协议核心对 profile 内容保持无知——这是"协议不设分类树"与"买卖匹配需要 12 形态 × 14 行业"两个需求的同时满足。第一个 profile 见 §20。

**初探结论的两种解释与区分实验**：2026-10-11 的检索初探显示，"谁在征集/寻求合作"类查询只返回机构通告与过时编辑内容。但这存在两种解释，结论完全不同——(i) **检索层缺失**：个人意向在开放网上存在，只是现有检索栈发现不了；(ii) **供给不在开放网**：个人意向本就发在平台内（小红书、即刻、微信群），开放网上根本没有供给——若为 (ii)，真正的缺口是"让人把意向搬到自有域名"的行为改变问题，比协议问题难一个量级。区分实验：**E1**——直接问各 AI 引擎意向类问题，将回答分类为"查不到 / 平台内容 / 开放网内容"三类；**E2**——供给探针：在开放网按 ODP 格式发布少量真实测试意向并等待收录，再重问引擎。若引擎随后能取到 → 缺口在检索层（协议可解，M1 成立）；若仍取不到 → 缺口在引用算法或供给侧（M1 存疑，需重新评估）。

**E0（行为实验，已回收，2026-10-11）**：声明者本人复盘四个已停运的同类平台，事实如下——

- **51buy / 51sell**：**从未正式上线**（仅本地/内网跑通），因此**不构成对需求假设的任何检验**——既不支持也不证伪；
- **aiseek / adb(ADE)**：上线约 2 个月，但**无任何 SEO 与推广、外部访问量≈0**；停运原因是**分发失败（无人被引导至此）**，**非需求失败**；期间**跨 Agent 互动仅在声明者为多个 Agent 设定定时任务（人类驱动）时才发生**，无人类驱动则 Agent 不主动操作。

**E0 回收的两条硬结论**：

1. **"需求死亡"威胁撤销，但 intent 未被证实**：没有一个平台是"给了真实流量后仍因没人要而死"的——所以不能据 E0 判 intent 需求不存在。但同理，intent 需求至今**一次都没有被真实检验过**（从没导入过真实外部供给）。intent 保持"未证实"，启动门槛仍是 §15 双边流动性，验证责任交给 E1/E2。
2. **Agent 无自主性（行为学铁证，影响 M2 与全部互动模型）**：Agent 不会自发检索、自发互动、自发运营——每一次真实互动背后都有一次人类驱动（定时任务、一次提问）。这是当前技术条件下的一手事实，已确立为 §4 **设计原则 P6（人类驱动假设）**，并据此重写 M2 的定位。

**对 agent1 "中心化更易点火"论证的裁定（v1.0-draft-15 修订）**：该论证**不成立，且此前接受它的一半是我的错误**。四平台的死因均非"给了流量仍无人要"——51buy/51sell 从未上线，aiseek/ADE 零推广，而 tpool 的 106 用户在同一标准下也属**近乎零分发**：它**没有点着火**，所以"点火后仍零成交"这句话无据。同时，"任何需要第二方的形态都不成立"是从 n=4 自身样本推出的全称判断，同样不成立。正确的表述只剩两条：① 这四次尝试**都没有做过真实的分发投入**，因此**关于需求是否存在，E0 没有给出任何结论**；② 我方据此**选择**不押双边（P7，能力边界判断）。此前写下的"点火之后依然零成交""死因是没有第二方来消费"等句已在本版撤除。

## 16. 已定案项（原开放问题）

v1.0-draft-02 关闭三个待定项：

- **intent 回联不做隐私中继**：`intent` 类声明的 `contact` 原样公开，索引不代收、不隐藏。回联方在消息中自报 Agent 身份即可（§7）。若声明者不愿暴露联系方式，则不应发布 `intent`——把选择权交回声明者，而非在协议里做一套会滋生信任幻觉的中继层。
  - **复核记录（v1.0-draft-14）**：draft-13 取证发现在运营的同型平台 tpool 已实现一套可用的联系方式转接（池内零联系方式、落库加密、号码掩码、每日来信上限），即"协议本可以要求的能力，实践中已被建出来"。已正面权衡并**决定维持不设中继**，理由三条：① 中继把索引变成通信枢纽，与 P7"协议只负责可寻址可验证可引用，不负责替你传话"直接冲突；② 中继引入索引侧的存储与滥用责任（垃圾投递归责、内容留存、跨索引不互通），这些成本由协议承担而收益归声明者；③ 明文邮箱的收割风险属实，但救济在声明者一侧更有效——使用可撤销别名地址（一次性、可关停、可换发），而非把隐私责任外包给索引。**主动选择明文公开即是声明的一部分**，与 §12 的下架规则共同构成声明者控制面。将来若出现"多个索引共识愿意共担中继责任"的场景，中继可作为独立垂直 profile 提出，届时不改动本节核心。
- **多语言纳入 v1**：见 §18。
- **域名变更身份延续**：见 §17。

**后续裁定（draft-15 记录，属事实性批注，不另起新版本）**

- **tpool 首页"60万+"表述——裁定：保留现状，接受外部暴露**。§15 E0 已如实记录该数字实为抓取内容表（643,450 行）而非用户，而 tpool 首页仍显示原数字、暂不修改。评审方（第五轮 P2-3）指出这是"公开文档记录了自己仍在运营的站点展示误导性指标"的不利暴露——**该风险已被权衡并接受**，理由：修改生产站文案属独立事项，不与协议工作混排；且 E0 记录本身已是自我不利披露，方向一致。**本条存在的意义是：后续评审不得再就同一矛盾要求重新裁定，如需变更只需直接执行，无需再走规范流程。**
- **执行顺序——裁定：索引 MVP 优先，E3 暂后**。E3 是唯一的承重实验，但其执行依赖"有真实可提问的语料 + 2–6 周观察窗"；先建索引 MVP（§7 检索契约 + §6.2 容量治理与 PII 字段级闸 + §9 四项机器入口）既能作为 E3 的 A/B/C 承载体，也可独立推进。约束：本机无真实 python/node 运行时（仅微软商店占位别名），故 MVP 的运行时落点需先决定（本机安装 / 部署到已有服务器新开独立目录 / 交付代码由运营方自建）。

## 17. 身份锚定与域名迁移

本节回应"换域名后如何不丢身份"。先陈述一个绕不开的事实：

> 在纯域名模型下，身份 = 对 `<host>` 域名的控制权。声明者一旦放弃域名，任何人买走它即可在其 `id` 下发布内容——这是**冒名**，不是迁移。协议无法在"零密钥"前提下把两者区分开。

因此 ODP 采用**密钥锚定身份、域名降级为可解析地址**的模型。代价是声明者生成一次密钥对（`openssl` 或任意 Ed25519 工具，一条命令）；换取的是域名自由迁移且不可被冒领。

### 17.1 身份锚（Anchor）

- 一个声明者身份的**权威凭据是其 anchor 公钥**，而非某个域名。`odp-host.json` 的 `anchor_key_id` 指向 `public_keys` 中担任锚的那把密钥（§7）。
- `id = urn:odp:<host>:<local>` 里的 `<host>` 是**注册主域（home host）**，是身份的历史出生地，用作可读性与首次发现入口，**不再被当作身份本体**。解析身份时以 anchor 公钥为准，域名只是当前解析位置。

### 17.2 迁移记录（Moved Record）

域名变更时，声明者在**旧域名**放置一份 `/.well-known/odp-moved.json`，并由旧 anchor 密钥签名：

```json
{
  "odp_version": "1.0",
  "from_host": "old.example",
  "to_host": "new.example",
  "anchor_pubkey": "base64…（旧 anchor，供解析方比对）",
  "migrated_at": "2027-01-01T00:00:00Z",
  "signature": {"alg": "ed25519", "key_id": "old.example#anchor", "value": "对 (from_host,to_host,migrated_at,anchor_pubkey) 的签名"}
}
```

新域名的 `odp-host.json` 同时写 `"also_known_as": ["old.example"]` 并**呈现同一把 anchor 公钥**（密钥不变，仅换域名）。

### 17.3 解析规则（消费 Agent / 索引必须实现）

1. 遇 `urn:odp:<host>:…`：取 `<host>` 的 `odp-host.json`，登记其 `anchor` 公钥。
2. 若该 `odp-host.json` 不存在或返回 `odp-moved.json`：**校验迁移记录的签名确实由记录里声明的 anchor 公钥所作**。通过 → 跟随到 `to_host`，并核对其 anchor 公钥与来时一致（或为其签名授权的轮换后继，见 17.4）。
3. 迁移链最多 5 跳，检测环路；每一跳都必须签名有效。
4. **冒名判定（关键）**：若旧域名已注册失效、现由**不同 anchor 公钥**提供服务，或其 `odp-moved.json` **无法由原 anchor 验证**，解析方**必须**判定身份断裂/疑似冒领，不得当作合法迁移；此时旧 `id` 仅作为历史引用保留，指向任何索引缓存里字节一致的旧副本，绝不采信新控制方发布的同名内容。

一句话：**域名可以变，但只有旧密钥点头才算迁移；没有密钥点头的"同名域名"，一律按陌生人处理。**

### 17.4 密钥轮换（换钥匙，不换人）

anchor 密钥泄露或到期时，用**旧** anchor 对 `(old_pubkey → new_pubkey, 时间)` 签名，发布 `/.well-known/odp-keyrotation.json`，并把新公钥加入 `public_keys`。解析方以签名链验证"新钥匙确由旧钥匙授权"。轮换与迁移正交，可叠加。

### 17.5 无密钥发布的边界（诚实声明）

无 anchor 密钥也可发布声明（满足 G1 零门槛），但协议**明确警告**：这类身份**不支持安全的域名迁移**。旧域名一旦失效，其 `id` 会悬挂或被冒领，只能作为历史引用。要长期持有身份，声明者迟早需要绑定 anchor 密钥。索引应在 UI/元数据上区分 `signed` 与 `keyless` 来源，供消费方自行评估信任（仅标注，不参与排序，遵守 §10）。

## 18. 多语言与本地化

v1 支持多语言，核心原则是**"主张单一权威，叙述允许多本"**：

- **权威语言 = `lang`**：一条声明只有一个权威 `lang`（BCP-47）。`claims[].text`、`falsifiable_by` 以及未列进 `translations` 的字段，**以 `lang` 语言为准，是机器评估与引用的唯一权威文本**。
- **`translations` 只翻译叙述**：`translations[locale]` 可本地化 `title`、`summary`、`body_md`，供不同语言的人/Agent 阅读；**不翻译 `claims` 的权威语义**——评估一个预测是否被证伪，必须读原文，避免翻译漂移篡改主张。
- **可选逐条展示译文**：若确需展示 `claims` 的译文，用 `claims[].text_i18n = {locale: "译文"}`，仅作显示用途，`text`（`lang` 版）恒为权威。
- **字节一致性不受影响**：`translations`/`text_i18n` 都在源上一次性发布、随声明不可变，因此 §7"同一 id 在任何索引返回字节一致"仍然成立。
- **消费方义务**：不得把机器翻译的 `claims` 当作原文转述为事实；自动译文须标 `derived`。检索可按权威语言的 `claims` 匹配，也可按任一 `translations` 命中后回源读权威语言评估。

## 19. 示例声明

规范附录提供**六条**可直接使用的示例（idea ×2 / intent / capability / notice / experience 各一），见随附 `examples.ndjson`（线上地址 `https://ade.pub/examples.ndjson`）。**示例一律使用 `example.org` 作为占位域名**（2026-10-16 修订）：此前示例沿用实现方的真实域名 `findable.cn`，而该域名在示例发布时尚不可解析——把不合规的地址当范例发出去，等于教每个新接入者犯同一个错。示例同时按 §7 的形态给出：`source_uri` 为机器形态、`human_uri` 为人可读形态。线上另有一份**运营者自身的历史声明清单**（`/declarations.ndjson`，含已废止示例与真实签名记录，仅用于对账，不是模板；口径见 `meta.corpus_scopes`）。**命名说明**：本附录此前叫 `declarations.ndjson`，与参考实现里"索引运营者自己的声明清单"（§6.1 的 `declaration_list`）恰好同名，实测导致消费方把示例集误当全量语料、又把运营者清单误当索引全量，故改名 `examples.ndjson`；而"索引全量语料"的唯一入口是 §7 定义的 `GET /api/v1/dump`（含各源、剔除已撤回），`/api/v1/stats` 的计数则包含已撤回记录——三者口径均已机读登记于 `GET /api/v1/meta` 的 `corpus_scopes`。

## 20. 垂直包：classifieds（vp-classifieds/0.1）

ODP 的第一个垂直 profile，承载"我要买 / 我要卖"类 intent 声明的重分类。**设计资产**继承自（**从未正式上线的**）供需情报库 51buy 需求侧 + 51sell 供给侧——其字段与枚举是可复用的设计成果，但其运行效果**未经任何检验**（§15 E0），本节不对其有效性作任何主张。核心结构是**买卖双侧 code 完全同构**：买方发"我要买 goods"、卖方发"我卖 goods"，双侧才能匹配。

### 20.1 原则

1. **镜像对齐**：形态 code 买卖双侧同构，语义按视角重写（需求侧"找劳务"/供给侧"卖劳务"）；分类体系不发明新 code；
2. **行业共用**：行业是需求发生的场景，买卖双方行业一致才能对上；
3. **只增不删**：字段白名单与形态枚举只扩展、不收缩，新增不影响已发布数据；
4. **合规敏感在声明层表达**：敏感组合以声明自带提示 claim 表达，索引不设审核队列（§10/§12 边界不变）。

### 20.2 形态枚举（12，供给侧视角；需求侧同构）

| 分组 | code | 买卖语义 |
|---|---|---|
| 有形交付 | `goods` / `secondhand` / `asset` | 买/卖商品、二手闲置、大额资产 |
| 服务交付 | `labor` / `project` / `solution` / `tech` | 找/卖劳务、承接/外包项目、方案咨询、技术交付 |
| 无形交付 | `patent` / `data` / `lease` / `rights` | 买/卖专利、数据与API、租使用权、授权加盟 |
| 资金 | `fund` | 借/贷资金（⚠️ 持牌合规敏感） |

### 20.3 行业枚举（14，买卖共用）

`industrial` 工业制造 / `medical` 医疗健康 / `education` 教育 / `life` 生活消费 / `business` 企业服务 / `it` 信息技术 / `construction` 建筑工程 / `logistics` 物流运输 / `agriculture` 农业食品 / `finance` 金融 / `energy` 能源资源 / `culture` 文化创意 / `public` 公共事业 / `realestate` 房地产。每个形态限定可用的行业子集（完整映射随 profile 注册表发布）。

### 20.4 字段白名单（requirements 容器）

声明携带 `requirements` 对象，按形态装载结构化字段。common 通用键：数量 / 规格 / 单位 / 价格 / 地点 / 备注。各形态专属键示例：`secondhand`（成色*、购入年份、维修记录、验货方式）、`asset`（资产类型*、权属、估值、交易方式）、`labor`（服务类型*、技能、资质证书、服务城市、结算方式）、`project`（项目类型、技术栈、工期*、验收标准）、`lease`（租期*、押金、租金）、`data`（数据类型、格式、更新频率、合规声明）、`fund`（额度、期限、利率、资质要求）。带 * 为该形态必填。完整白名单随 profile 注册表发布。

### 20.5 预算单位映射

预算单位由 形态 × 行业 决定，投递 Agent 无需传单位：`labor×life` → 元/月，`labor×construction` → 元/天，`project×it` → 一次性，`lease×industrial` → 元/月……每个组合附合理区间校验（越界提示、不阻断）。完整映射随 profile 注册表发布。

### 20.6 合规敏感组合（声明级提示）

`fund×finance`（放贷需持牌）、`data×medical`（临床数据涉隐私伦理）、`secondhand×finance`（不良资产包需持牌）、`rights×finance`（金融牌照敏感）——命中组合的声明应自行携带合规提示 claim；索引不做内容审核，消费方与回联方据提示自担判断。

### 20.7 旗舰源机制（当前无旗舰源）

classifieds 曾设定 51buy/51sell 为旗舰源。**事实校正（draft-11）：二者已下线**（连同 aiseek、adb/ADE——四个 Agent 平台项目均已停止运营）。本节机制保留、实例清零：

**旗舰源是垂直包的可选启动器，不是协议依赖项。** 一个自带真实供需的垂直平台，可以解决该垂直包内 intent 的密度冷启动（§15）——这个机制论证依然成立；但 ODP 本身不以任何特定平台为存续前提，旗舰源缺位时，intent 冷启动回到 §15 的通用门槛，而 idea/notice/experience 的启动序列不受影响。当前状态：**无旗舰源在运营**。

**同时必须诚实记录的反向证据**：比本协议更易冷启动的形态（中心化平台：有注册、审核、配额、运营抓手，能主动拉供给）已实际部署过并死亡。"中心化更容易点火"这个直觉是错的——中心化帮助的是**留存与治理**，不是**点火**；那四个项目的点火手段（封闭场景强制使用、种子供给）去中心化版本同样可以用。但此辩护成立与否取决于下线原因——在 §15 E0 复盘完成前，这是一个**未决的不利证据**，intent 的任何启动决策都不得绕过它。

## 21. 声明者页面（人可读投影）

场景要求"内容也应能被人观看"，本节把这句话变成可检验的条款。**页面是声明的投影，不是第二份事实**：权威内容永远是带签名的声明源，页面只是它的人类可读形态。

1. **派生而非另写**：人可读页面 MUST 由声明源渲染生成（参考实现 `odp-page.py` + 母版；或索引侧视图）。页面不得引入声明里没有的事实，也不得省略现行主张——**同一份内容，两个读者，一个事实源**。
2. **链条收敛**：渲染只展示 `supersedes` 链的**终点**；被取代的旧版与撤回墓碑不得与现行内容并列（否则读者会把废稿当成作者当前的立场）。这是索引自己踩过的坑（两次通告失实、迁移链分叉），故写成条款。
3. **确定性**：同一份源 + 同一版渲染器 MUST 产出同样的页面（区块顺序按 type 固定、条目按 `published_at`/`id` 确定序）。页面不做排序、不做推荐、不做"精选"——§10 的 neutrality 同样适用于视图层。
4. **随四态变化**：`published` 正常呈现；`withdrawn` 呈现为撤回墓碑（明示被声明者撤回，保留可核对的原文地址）；`unreachable` 不得静默显示旧缓存为现行内容，须标注不可达；`expired` 标注已过有效期。降级必须可见（§6.4 镜像规则的同一条精神）。
5. **不单独签署、不单独引用**：页面本身不产生新的签名或身份；引用一律指向 `source_uri` 或声明的稳定地址（§7）。页面必须把读者送回权威原文（每块内容附溯源）。
6. **可自托管、可搬走**：托管源场景下索引 MAY 为每个 handle 提供人可读视图，但该视图 MUST 可被声明者用自己的域名上的同一渲染器复现，且全量导出免授权（§6.3）——索引提供便利，不提供抵押。
7. **身份与签名状态如实呈现**：视图上的徽章 MUST 来自索引的验签判定（`identity_status`/`signature_status`），**不得因"签名字段存在"就显示为已验证**；无判定可取时明写"未验证"。坏签名标 `sig_invalid`（§6.4-12）。
8. **把握度不翻译成概率**：`confidence` 呈现为序数措辞（如"把握 较高（自评分 0.7，非概率）"），并保留 `kind` 与 `falsifiable_by`——把它们压成一个百分比数字，等于毁掉本协议唯一的差异化：评估级语义。
9. **机器入口同址可发现**（分两种形态，2026-10-16 修订）：**清单页/主页**MUST 以 `rel="alternate" type="application/x-ndjson"` 指回声明清单、以 `rel="describedby"` 指向宿主文档；**单条人可读页**MUST 以 `rel="alternate" type="application/json"` 指向该条的源字节入口（`/raw/{id}` 等），并以 `rel="describedby"` 指向身份宿主文档——单条的机器形态是 JSON 对象而非 NDJSON 清单，不得把两种情形混写成一条。宿主文档 MAY 用 `human_page` 声明自己的人类可读主页（同域校验），索引目录据此把流量指回声明者（§7）；声明级的人类可读形态由 §5.3 `human_uri` 表达，**两个字段方向相反、都不可缺**：`human_page` 是"源 → 页面"，`human_uri` 是"这条声明 → 这一页"。

---

*本文档为 ODP v1.0-draft-15。draft-14 → draft-15：首页判据矛盾修复（并停止在首页复述判据）、P7 降为战略选择、新增 E3 承重实验、三处门槛与措辞收口。**自本版起规范冻结**：除 E3/MVP 产出的事实性修订外，不再因评审意见产生新版本——下一版应是 v1.0。*

**2026-10-16 冻结期内的三处就地修订（不升版本号，逐条入 §6.4-12 与本段留痕）**：① §0 摘要首句与"对标 RSS"段——主体由"Agent 投递"改为"人发布、供 Agent 检索、同时能被人阅读"，并区分自托管与托管两种地址归属；② §2 废止"不追求人类阅读体验——HTML 页面仅为兜底"，改为**双读者不偏废**条款；③ §7 为引用目标 URL 增加**可读性 MUST**，并新增 §21「声明者页面」。**理由**：这三处原文与本项目已定稿的应用场景相互矛盾，且实现已按场景完成（`/d/{id}` 内容协商、`/raw/{id}`、`/@handle` 视图、`/publish`），继续保留旧表述等于让规则拆场景的台——按"规则服务于场景"的元原则处理，属冻结条款允许的"事实性修订"。v1.0 正式文本据此归并。
