diff --git a/20-product-tdd/capture-contract.md b/20-product-tdd/capture-contract.md new file mode 100644 index 0000000..7ed3a13 --- /dev/null +++ b/20-product-tdd/capture-contract.md @@ -0,0 +1,41 @@ +# Capture Extension 合同 + +`inkcre/capture` 是 first-party extension,拥有材料、来源、采集图、收入身份和恢复语义。各平台 Distribution 为所在 Peer 提供这些能力;语言和仓库不决定业务中心。声明支持采集的分发在本 Peer 内完成采集、编辑、本机保存、构图和共享写入,不依赖另一个分发补齐收入流程。 + +原生 Mac 分发通过 PostgreSQL 原生协议操作共享 info-base。Host 提供连接、同连接事务与标准 Block/Relation/Storage 基础操作;Capture 编排业务事务。Python 仓库拥有权威 schema/迁移的交付,不因此成为运行时采集执行者。其他 Peer 按自身能力读取或提供采集分发。 + +## 材料与持久图 + +材料包含提交 UUID `submission_id`、采集时间 `captured_at`、入口 `selection | paste | screenshot | manual`、可缺失的 `origin`、有序 `materials` 和可缺失的 `annotation`。出处的应用 ID、标题和 URL 允许缺失;显式粘贴不推断来源。材料和附注不能同时为空。单次至多 128 份材料,文字与附注 UTF-8 加原图 bytes 累计不超过 32 MiB。 + +支持 PNG、JPEG、GIF、WebP,验证 MIME、实际格式与解码尺寸。已有支持编码保留原 bytes;系统仅提供原生位图时,由平台分发生成 PNG 后作为本次原图。原文和自己的补充保持可区分,OCR、模型处理不阻塞收入。 + +| 对象或关系 | 合同 | +| --- | --- | +| 根 Block | `extensions.capture.capture.v1`,JSON 内容包含提交身份 `submission_id`、材料摘要 `payload_digest`、采集时间、入口、出处 | +| 根 → 材料 | 从 `material:0` 连续递增,无重复序号 | +| 文字 | `core.text.v1`,保持原文 | +| 图片附件 | `extensions.capture.attachment.v1`,JSON 内容包含 MIME、可选文件名 | +| 图片附件 → 内容 | 唯一 `content` 关系,目标为 `core.image.v1` | +| 原图 | 标准 PostgreSQL binary storage `-4`,使用标准 `{"blob_id":"…"}` 指针 | +| 根 → 用户附注 | 至多一条 `annotation` 关系,目标为 `core.text.v1` | + +读取分发按关系解释顺序和附注,畸形关系显式报错。Web 来源只允许 HTTP(S) 点击。信息属于共享 info-base,读取不依赖采集设备本地路径或原分发存活。 + +## 收入、事务与恢复 + +用户确认后在本机冻结 UUID、材料和目标;草稿、待办与确认结果由本机持久化保存。Capture 在事务外完成校验和构图,再于同一数据库连接、同一事务内锁定提交身份、查找现有 Capture 根、写图与原图 bytes。任何写入错误整体回滚。并发重试以 UUID 字符串的 `hashtextextended(value,0)` 取得事务 advisory lock。 + +Capture 根的 `submission_id` 与 `payload_digest` 用于提交恢复。相同身份和摘要返回现有根;摘要冲突保留本机材料并要求处理。Extension 不拥有独立共享表,也不在 Extension state 中累积提交回执。图和原图使用既有 Block/Relation/Storage;本机确认后保存根 ID 和时间,再清理本机材料。 + +材料指纹为规范 JSON 的 SHA-256:键排序、紧凑 UTF-8、缺失可选值为 null、时间 UTC 六位小数、图片数据替换为 bytes SHA-256。文本换行及 Unicode 组合形式不变,材料顺序不变。本机时间冻结为毫秒精度,再规范化为上述时间文本。 + +网络超时不证明提交失败。恢复查询原目标中的 Capture 根并核对材料摘要;没有根时以原身份重试。明确提交成功或恢复核对成功前保留本机材料。更改当前连接不重定向待办;用户再次采集同内容使用新 UUID,不按内容去重。已经在本机确认的记录不再发送。提交响应丢失后、恢复前又由其他 Peer 删除根的窄窗口不提供防重建保证;不为此保留永久回执或墓碑。 + +## 平台分发与启停 + +Capture 的本机草稿格式、待办状态机、系统采集策略和界面属于其平台分发。Host 提供应用、窗口/命令挂载、凭据、持久目录和扩展生命周期。停用某个 Peer 的 Capture 不删除材料或改变共享 schema。 + +Swift 原生分发以 `swift_bundled` 标识,随签名应用携带精确 producer manifest;扩展版本独立于应用版本。未配置数据库时可本机运行。本机运行开关只控制本机入口与任务,不隐式修改当前或其他信息库的共享参与。首次加入创建缺失的参与记录,已有选择必须读取且不得覆盖;加入成功后,重连不重建已移除的参与,不用缓存启用值覆盖共享意图。用户可以明确指定信息库,选择并启用当前应用携带的版本;该操作允许更新旧版本选择或重新创建缺失的参与,无需动态下载。共享写入前仍复核精确版本与启用意图,本机启动不覆盖其他 Peer 的停用决定。 + +此 Capture 合同尚未发布,采用一个原生收入协议,不提供旧 HTTP 提交 API、历史本机格式迁移。平台通用数据库协议仍保持原生与 HTTP 的权限对等;未来 HTTP 收入实现须明确自己的事务入口。 diff --git a/20-product-tdd/extension-release-and-installation.md b/20-product-tdd/extension-release-and-installation.md index 6f535bc..86d83b6 100644 --- a/20-product-tdd/extension-release-and-installation.md +++ b/20-product-tdd/extension-release-and-installation.md @@ -12,6 +12,16 @@ Extension 发布者、Registry、开发工具和宿主共同消费本契约。Re prepare、upload、publish 一次针对一个 Native Release。只有它自己的全部原生对象齐备时才可公开,检查与提交之间改变产物身份或关联必须重新验证。发布 Python 不等待 MF,发布 MF 不等待 Python。已发布的坐标及产物身份不可覆盖;相同请求可幂等重试,冲突需要新版本。文档不使缺少可执行产物的分发成为可安装版本。 +共享参与协议中的 Distribution 是开放的非空字符串,不枚举语言、打包方式或现有宿主。各宿主报告自己支持的格式,并在实际加载边界校验;一个新宿主不需要修改共享数据库的格式白名单。Registry 只对自己能交付的产物提供安装能力。 + +Extension 不拥有独立共享数据表。资料使用 Block/Relation/Storage,共享配置与业务状态使用已有 Extension config/state;仅本机需要的草稿、队列和运行状态保存在本机。 + +## 随签名应用交付的原生分发 + +`swift_bundled` 表示宿主签名应用携带的原生分发。producer manifest 定义 Extension Name、分发格式和精确版本,由模块资源与签名应用一起交付。宿主只运行实际携带的模块,不下载动态代码、不替换精确选择;需要其他版本时明确要求更新应用。其产物供应链是签名应用,不把不存在的 Registry 发布或原生热加载能力作为已完成事实。 + +此分发仍有真实启停生命周期和 Peer 参与记录;应用关闭只停止实际运行,不撤回共享启用意图。未配置数据库时可离线使用扩展。首次加入与重连须区分:首次事务内创建缺失的参与,冲突则读已有值;加入或明确启用成功后,重连不重建已移除记录、不重放离线开关。用户在线明确启用可以重新创建本 Peer 的缺失参与;离线操作只改变本机运行并显示共享意图尚未更新。共享写入前复核参与选择和启用意图。Python/MF 原生产物继续按各自 Registry 发布流程交付。 + ## 部署共享状态与 Peer 参与 部署中一个插件只有一个逻辑身份及其共享配置、业务状态。安装选择属于 `Peer × Extension`:该 Peer 选择一种宿主支持的 Distribution 及精确版本,并保存自己的启用意图。数据库保存这些持久事实;运行端报告实际加载的分发、版本和运行结果。 @@ -43,7 +53,7 @@ prepare、upload、publish 一次针对一个 Native Release。只有它自己 宿主在改变运行状态前校验目标坐标、发布状态、元数据、原生产物和 SDK 条件。启用成功须包含完成启动和相应副作用;持久化失败需要按宿主生命周期清理或报告真实未收敛状态。保存目标版本不等于升级完成。 -显式启用和停用命令先保存参与意图,再应用运行变化;运行失败保留意图并报告实际错误,不以运行成功回调重新写入意图。自动恢复只消费已有意图,不能将用户已撤回的启用写回。宿主串行处理同一参与记录的生命周期,并在异步初始化或激活后复核精确选择与启用意图;若意图已撤回或版本已变,清理迟到实例,不将它报告为当前运行结果。该串行边界只协调当前宿主,不能排除其他已准入客户端的数据库写入,也不保证持久意图与进程状态瞬时原子切换。 +针对共享参与的显式启用和停用命令先保存参与意图,再应用运行变化;运行失败保留意图并报告实际错误,不以运行成功回调重新写入意图。原生宿主的本地停用先保存本机停用状态并停止运行,再尝试更新共享意图;连接、凭据或授权错误不能阻止本机停止,也不能将共享更新报告为成功。自动恢复只消费已有意图,不能将用户已撤回的启用写回。宿主串行处理同一参与记录的生命周期,并在异步初始化或激活后复核精确选择与启用意图;若意图已撤回或版本已变,清理迟到实例,不将它报告为当前运行结果。该串行边界只协调当前宿主,不能排除其他已准入客户端的数据库写入,也不保证持久意图与进程状态瞬时原子切换。 离线 Peer 只能接收待应用选择,不能被宣称已停止旧实例或已运行新版。租约过期不证明进程停止。Python 等宿主若安装会修改共享原生依赖环境,应暂停该 Peer 的执行,安装后从新进程启动;只停目标插件不足以证明其他已加载依赖安全。应用失败应报告失败或待处理,不能假定自动恢复旧环境或撤销插件已经执行的业务迁移。具体进程、打包和恢复操作留在宿主本地文档。 diff --git a/20-product-tdd/local-files-contract.md b/20-product-tdd/local-files-contract.md new file mode 100644 index 0000000..304eac0 --- /dev/null +++ b/20-product-tdd/local-files-contract.md @@ -0,0 +1,37 @@ +# 本地文件扩展合同(候选 v1) + +`inkcre/local-files` 将指定 Peer 可访问的文件持续收入同一 info-base。执行分发拥有目录访问、监视、提取与对账;读取分发解释同一份图。原文件留在原 Peer 的文件系统,数据库保存已提取正文和位置引用。其他 Peer 阅读正文无需原 Peer 在线。首版不提供原件传输、备份、OCR 或历史版本。 + +## 位置与来源 + +原件位置为 `inkcre-peer-file:///<机器绝对路径>`。例如 `inkcre-peer-file://a143b185-f43d-47d1-8ef7-1d3857284b01/Users/alice/note.md`。authority 是 Peer UUID,path 是绝对路径;空格、中文、`#`、`?` 按 URI 编码。禁止凭据、端口、query、fragment 和 NUL。URI 不授权文件访问,也不注册系统 URL handler。只有匹配 Peer 的执行分发可以按现有文件权限打开原件;其他读取端显示位置,不把它当作可远程下载的 URL。 + +目录 Source 类型是 `extensions.local_files.directory.v1`,config 包含 `peer`(UUID)、`path`(绝对目录路径)、`enabled`(布尔值),不接受其他字段。其普通采集参数为空对象。Source 的 `core.source.v1` 锚点通过 `manages` 关系指向本来源管理的文件资料。只领取 `config.peer` 等于当前 Peer 且已获得目录访问能力的 `core.source.collect.v1` Job。读取分发只注册 Resolver,不注册无法执行的 Source 类;catalog 中存在类型不代表本 Peer 具有执行能力。 + +FSEvents 等平台通知触发被动核对;手动扫描使用普通 Source Job。两者执行相同对账逻辑。同一 Source 串行运行。Source 与原信息库及 Peer 绑定,切换当前连接不迁移来源。暂停停止监视及后续提交;移除经确认后删除 Source,已经收入的图保留。 + +## 文件资料与正文 + +文件根 Block 使用 `extensions.local_files.file.v1`,content 为以下 JSON。成功提取后恰有一条 `body` 关系指向 `core.text.v1`;首次提取失败时可没有正文。用户批注或其他组织关系不属于本扩展更新范围。 + +| 字段 | 合同 | +| --- | --- | +| `location` | 上述位置 URI。位置可以随文件重命名改变,Block ID 保持稳定。 | +| `format` | `pdf`、`docx`、`markdown`、`org`、`html`、`text`。 | +| `identity` | 可省略;含 `volume` 字符串、`number` 非负整数、`created` UTC 时间,用于证明同一文件在原 Peer 的移动。它不是内容摘要或跨 Peer 身份。 | +| `available` | 最近完整核对时原件是否存在;无法访问目录不等于不存在。 | +| `observed_at` | 此状态的 UTC 观察时间。 | +| `revision` | 可省略;最后成功正文对应的 `sha256`(原始文件字节)、`extractor`(提取实现版本)、`extracted_at`(UTC)、`scope`(`text`、`text_layer`、`main_document`)。 | +| `issue` | 可省略;当前提取失败的可读原因。失败不能清空旧正文或替换成功修订。 | + +更新先按本来源中的当前路径匹配,以支持编辑器原子保存。旧位置消失且系统身份唯一证明重命名时更新原资料;否则创建新资料,不能依据内容相同合并两个文件。身份需持久保存,重启后仍可核对。摘要只判断修订。 + +单份文件元数据、正文和关系在一个事务中写入。提交回包丢失后重新读取共享图,避免重复创建。删除原件保留最后成功正文,将 `available` 改为 false;这不是软删除或回收站。只有完整枚举成功且目录仍可访问,才可认定原件缺失。目录离线、权限失败、取消扫描不得批量标记缺失。断网后重连核对当前文件,不承诺保存离线期间出现又消失的文件。 + +Source state 包含最近完整扫描时间 `scanned_at`、失败文件数 `errors`、可选 `issue`。部分提取失败仍完成目录核对,但主动 Job 以 failed 关闭并呈现失败数量;取消、超时按普通 Job 终态处理。 + +## 文字提取范围 + +PDF 提取文字层并分隔页面;无文字层、加密和损坏分别报告。DOCX 首版提取主文档文字与表格单元格,不含脚注、批注等附属内容;读取界面须呈现 `main_document` 范围。Markdown、Org、纯文本保留原语法和换行,不执行代码或 include。HTML 只解析本地 DOM,剔除脚本、样式与模板,保留基本段落,不执行脚本或下载外链。 + +首个 Swift 分发的 extractor 为 `mac-native-text.v1`。输入上限 64 MiB,输出 UTF-8 正文上限 8 MiB;超限报错,不截断后标成功。空白文本允许为空正文,但 PDF/DOCX 没有可提取文字是失败。文本支持 UTF-8、带 BOM 的 UTF-16;不能可靠解码时报告失败。 diff --git a/20-product-tdd/unit-topology.md b/20-product-tdd/unit-topology.md index 2f17fae..f6f5981 100644 --- a/20-product-tdd/unit-topology.md +++ b/20-product-tdd/unit-topology.md @@ -11,7 +11,7 @@ Define cross-unit technical boundaries and ownership so changes do not leak resp ## Database Peer Topology -- `impl-py`, `impl-ts`, and future units are peer nodes; frontend/backend hierarchy is not +- `impl-py`, `impl-ts`, `impl-swift`, and future units are peer nodes; frontend/backend hierarchy is not part of the durable topology. - Native PostgreSQL and PostgREST are transports over one admitted database protocol, not separate semantic authorities. @@ -22,6 +22,9 @@ Define cross-unit technical boundaries and ownership so changes do not leak resp - Peer equality does not imply identical execution ability. A business facade may execute locally on a capable Peer or delegate one exact synchronous capability to another live Peer without turning the deployment into a fixed frontend/backend hierarchy. +- `inkcre/capture` 是 first-party extension,拥有跨平台的材料、采集图与收入语义。Mac 原生分发在本 Peer 内完成采集、持久待办、构图与共享写入;Host/Core 提供通用运行和数据库能力。 +- `inkcre/local-files` 拥有目录来源、文件位置引用、正文与持续更新合同。具备文件访问能力的分发直接收入,读取分发解释已存正文,不要求执行 Peer 在线;见[本地文件合同](local-files-contract.md)。 +- Mac 使用 PostgreSQL 原生协议,Web 按浏览器运行能力使用 PostgREST;传输选择不划分 Peer 业务权威。仓库维护位置不构成运行时流水线。具体语义见[Capture Extension 合同](capture-contract.md)。 - Shared actors,assets,trust boundaries and proportional security classification use the [Security Boundary Model](security-boundary-model.md)。Each Unit still owns its executable admission,rendering,runtime and deployment mechanics。 diff --git a/docs/index.md b/docs/index.md index 3a4733f..0d00e4e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,6 +9,8 @@ - [Cross-unit contracts](../20-product-tdd/cross-unit-contracts.md) - [跨 Peer 可观测性契约](../20-product-tdd/observability-contract.md) - [Twitter 归档信息与接入契约](../20-product-tdd/twitter-archive-contract.md) +- [主动采集持久化契约](../20-product-tdd/capture-contract.md) +- [本地文件位置与持续收入合同](../20-product-tdd/local-files-contract.md) - [Knowledge capability contract](../20-product-tdd/knowledge-capability-contract.md) - [Semantic retrieval and Peer capabilities](../20-product-tdd/semantic-retrieval-and-peer-capabilities.md) - [Feature retrieval and media interpretation](../20-product-tdd/feature-retrieval-and-media-interpretation.md)