From 29733914a4fcf03d59e78421786293cdf0392101 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Sun, 4 Oct 2026 18:49:51 +0800 Subject: [PATCH] =?UTF-8?q?docs(documents):=20=E5=A5=91=E7=BA=A6=20v0.59?= =?UTF-8?q?=20=E5=B7=B2=E5=8F=91=E5=B8=83=20=E2=80=94=E2=80=94=20=E6=9B=B4?= =?UTF-8?q?=E6=AD=A3=20W6=20=E9=82=A3=E6=89=B9=E3=80=8C=E6=9C=AA=E5=8F=91?= =?UTF-8?q?=E5=B8=83/=E5=BE=85=E5=8F=91=E5=B8=83=E3=80=8D=E7=9A=84?= =?UTF-8?q?=E8=BF=87=E6=97=B6=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cyrene_v2/Docs/api-client.md 已发布 v0.59(§1.2「文档存储与摄取契约」+ 端点表 16/17), 而 W6 那批文件的 KDoc 仍写着「契约尚未发布 / 待发布」,会误导后来人以为形状没有契约背书。 已逐条核对:我们实现的形状与已发布契约**完全一致** —— multipart 部件名 `file`、 201 首次 / 200 + `deduped:true` 去重、单文件 20 MiB、单回合 ≤5 条、上行只收 `name`、 `url` 是相对路径、`mime` 是嗅探基类型、`documents` 数组含 `chars`/`truncated`/`status`、 0 个附件时该键省略、4 个错误码。白名单在契约里也已更正为 22 项(与代码一致)。 纯注释更正,零行为变更。 --- app/src/main/kotlin/top/yeij/cyrene/data/api/DocumentsApi.kt | 2 +- app/src/main/kotlin/top/yeij/cyrene/data/api/dto/ChatDto.kt | 2 +- .../main/kotlin/top/yeij/cyrene/data/api/dto/DocumentDto.kt | 2 +- .../main/kotlin/top/yeij/cyrene/data/api/dto/MessageDto.kt | 2 +- .../kotlin/top/yeij/cyrene/domain/chat/DocumentFailure.kt | 2 +- .../main/kotlin/top/yeij/cyrene/domain/chat/DocumentStatus.kt | 2 +- .../kotlin/top/yeij/cyrene/data/api/dto/DocumentDtoTest.kt | 4 ++-- .../top/yeij/cyrene/data/repository/DocumentRepositoryTest.kt | 4 ++-- .../top/yeij/cyrene/domain/chat/DocumentDeliveryTest.kt | 2 +- .../kotlin/top/yeij/cyrene/domain/chat/DocumentFailureTest.kt | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/main/kotlin/top/yeij/cyrene/data/api/DocumentsApi.kt b/app/src/main/kotlin/top/yeij/cyrene/data/api/DocumentsApi.kt index 188c2a1..9092027 100644 --- a/app/src/main/kotlin/top/yeij/cyrene/data/api/DocumentsApi.kt +++ b/app/src/main/kotlin/top/yeij/cyrene/data/api/DocumentsApi.kt @@ -12,7 +12,7 @@ import retrofit2.http.Streaming import top.yeij.cyrene.data.api.dto.DocumentUploadResponse /** - * 文档存储端点(契约 **v0.59 待发布**,形状依据见 `02-前后端协同事项.md` 回执五 §一 S1)。 + * 文档存储端点(契约 **v0.59 已发布(api-client.md §1.2「文档存储与摄取契约」)**,形状依据见 `02-前后端协同事项.md` 回执五 §一 S1)。 * 权限 `owner|admin`。与图片链路([UploadApi] + `/api/v1/files/{name}`)**刻意分离**: * * | | 图片 | 文档 | diff --git a/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/ChatDto.kt b/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/ChatDto.kt index 815086d..d209995 100644 --- a/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/ChatDto.kt +++ b/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/ChatDto.kt @@ -35,7 +35,7 @@ data class ChatRequest( val stream: Boolean? = null, val clientMsgId: String? = null, /** - * 本回合附带的文档引用(契约 v0.59 待发布,形状见 [DocumentRefDto]):**≤5 条**, + * 本回合附带的文档引用(契约 v0.59 已发布(api-client.md §1.2「文档存储与摄取契约」),形状见 [DocumentRefDto]):**≤5 条**, * 每条**只给服务端存储名**(`{"name":"<32hex>."}`),**不收 URL**。 * * 上行只发 `name`:其它字段服务端一律不采信并覆盖(字节嗅探是唯一的类型裁决)。 diff --git a/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/DocumentDto.kt b/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/DocumentDto.kt index a9f6e54..d11eac1 100644 --- a/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/DocumentDto.kt +++ b/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/DocumentDto.kt @@ -3,7 +3,7 @@ package top.yeij.cyrene.data.api.dto import kotlinx.serialization.Serializable /** - * 文档 DTO —— 「文件进对话」的**唯一形状落点**(契约 **v0.59 尚未发布**)。 + * 文档 DTO —— 「文件进对话」的**唯一形状落点**(契约 **v0.59 已发布(api-client.md §1.2「文档存储与摄取契约」)**)。 * * ## 形状从哪来 * 写这份代码时 `Cyrene_v2/Docs/api-client.md` 的最新契约版本仍是 **v0.58**(里面**没有** diff --git a/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/MessageDto.kt b/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/MessageDto.kt index 9d3266e..134f2f3 100644 --- a/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/MessageDto.kt +++ b/app/src/main/kotlin/top/yeij/cyrene/data/api/dto/MessageDto.kt @@ -31,7 +31,7 @@ data class HistoryMessageDto( */ val clientMsgId: String? = null, /** - * 这条消息携带的文档引用与抽取统计(契约 v0.59 待发布;形状见 [DocumentRefDto])。 + * 这条消息携带的文档引用与抽取统计(契约 v0.59 已发布(api-client.md §1.2「文档存储与摄取契约」);形状见 [DocumentRefDto])。 * * 默认 [emptyList] 同时吃掉后端**尚未定死**的两种「0 个附件」形状: * **键缺失 → 空列表**(后端 `historyMessage.Documents` 带 `omitempty`,空/缺失即整键省略—— diff --git a/app/src/main/kotlin/top/yeij/cyrene/domain/chat/DocumentFailure.kt b/app/src/main/kotlin/top/yeij/cyrene/domain/chat/DocumentFailure.kt index ff5f249..687289b 100644 --- a/app/src/main/kotlin/top/yeij/cyrene/domain/chat/DocumentFailure.kt +++ b/app/src/main/kotlin/top/yeij/cyrene/domain/chat/DocumentFailure.kt @@ -4,7 +4,7 @@ import top.yeij.cyrene.core.error.CyreneError import top.yeij.cyrene.data.api.CyreneException /** - * 文档操作失败(上传 / 取值)。契约 **v0.59 待发布**,错误码依据见 + * 文档操作失败(上传 / 取值)。契约 **v0.59 已发布(api-client.md §1.2「文档存储与摄取契约」)**,错误码依据见 * `02-前后端协同事项.md` 回执五 §一 S1 与 §五「v0.59 会登记什么」。 * * ## 为什么要把错误码收成类型 diff --git a/app/src/main/kotlin/top/yeij/cyrene/domain/chat/DocumentStatus.kt b/app/src/main/kotlin/top/yeij/cyrene/domain/chat/DocumentStatus.kt index 81b1a54..06ad7fe 100644 --- a/app/src/main/kotlin/top/yeij/cyrene/domain/chat/DocumentStatus.kt +++ b/app/src/main/kotlin/top/yeij/cyrene/domain/chat/DocumentStatus.kt @@ -1,7 +1,7 @@ package top.yeij.cyrene.domain.chat /** - * 文档抽取状态(契约 **v0.59 待发布**,形状依据见 `02-前后端协同事项.md` 回执五 §一 S3-A/S3-B)。 + * 文档抽取状态(契约 **v0.59 已发布(api-client.md §1.2「文档存储与摄取契约」)**,形状依据见 `02-前后端协同事项.md` 回执五 §一 S3-A/S3-B)。 * * **开放集合,不用 enum**:后端的 `status` 是自由字符串,客户端映射只认这三个已知值, * **未知值原样保留**(不丢弃、不报错、不占位符)——与 `mode` / `platform` / `mood` 同一口径。 diff --git a/app/src/test/kotlin/top/yeij/cyrene/data/api/dto/DocumentDtoTest.kt b/app/src/test/kotlin/top/yeij/cyrene/data/api/dto/DocumentDtoTest.kt index 54eaddd..e0f81be 100644 --- a/app/src/test/kotlin/top/yeij/cyrene/data/api/dto/DocumentDtoTest.kt +++ b/app/src/test/kotlin/top/yeij/cyrene/data/api/dto/DocumentDtoTest.kt @@ -15,14 +15,14 @@ import top.yeij.cyrene.domain.chat.DocumentStatus /** * 文档 DTO 的形状钉子。 * - * **形状来源:`Cyrene-For-Android/devdocs/02-前后端协同事项.md` 回执五,契约 v0.59 尚未发布** + * **形状来源:`Cyrene-For-Android/devdocs/02-前后端协同事项.md` 回执五,契约 v0.59 已发布(api-client.md §1.2「文档存储与摄取契约」)** * (写这些用例时 `Cyrene_v2/Docs/api-client.md` 最新仍是 v0.58,没有 documents 条目)。 * 字段集与取值另对齐后端已落库实现与它的测试: * `407c934`(S1 存储端点 `documents.go` 的 `documentResponse`)、 * `5b2b385`(S3.5 文档多值化:`history.go` 的 `historyMessage.Documents` 带 `omitempty`、 * `history.DocumentRef` 的 `omitempty` 口径、`history_document_test.go` 钉住的元素字段集 * `chars,mime,name,size,status,truncated` 与它用的真实取值)。 - * **没有 v0.59 抓包**:这里的 JSON 是按上述实现形状逐字节手写的(唯一确认过的真实取值 + * **没有 v0.59 的真实抓包(形状按 api-client §1.2 与后端实现逐条核对)**:这里的 JSON 是按上述实现形状逐字节手写的(唯一确认过的真实取值 * 来自后端自己的测试夹具)。 * * 解码器用 [ApiClientFactory.json](与生产同一份配置),所以这里过不了的形状线上也过不了。 diff --git a/app/src/test/kotlin/top/yeij/cyrene/data/repository/DocumentRepositoryTest.kt b/app/src/test/kotlin/top/yeij/cyrene/data/repository/DocumentRepositoryTest.kt index bf01d9c..d508baf 100644 --- a/app/src/test/kotlin/top/yeij/cyrene/data/repository/DocumentRepositoryTest.kt +++ b/app/src/test/kotlin/top/yeij/cyrene/data/repository/DocumentRepositoryTest.kt @@ -22,12 +22,12 @@ import java.util.concurrent.Executors * 文档端点的**线级**行为:真 OkHttp + 真 Retrofit + JDK 自带 HTTP 服务端(与 * [UploadRepositoryTest] / [ChatRepositoryTest] 同一手法,不引新依赖)。 * - * **形状来源:`02-前后端协同事项.md` 回执五,契约 v0.59 尚未发布** + * **形状来源:`02-前后端协同事项.md` 回执五,契约 v0.59 已发布(api-client.md §1.2「文档存储与摄取契约」)** * (`api-client.md` 最新仍是 v0.58,没有 documents 条目)。夹具逐字段对齐后端实现: * `documents.go` 的 `documentResponse`(`{name,url,mime,size,sha256,deduped}`,`url` 是 * **相对**路径、`201` 首次 / `200` 去重)与它的错误码常量、 * `chat_documents.go` 的 `too_many_documents`、`maxChatDocuments = 5`。 - * **没有 v0.59 抓包**:响应体是按实现形状手写的。 + * **没有 v0.59 的真实抓包(形状按 api-client §1.2 与后端实现逐条核对)**:响应体是按实现形状手写的。 * * 要证明的四件事: * 1. 请求**真的是 multipart**、部件名真的是 `file`、**文件名(含扩展名)原样发出**、 diff --git a/app/src/test/kotlin/top/yeij/cyrene/domain/chat/DocumentDeliveryTest.kt b/app/src/test/kotlin/top/yeij/cyrene/domain/chat/DocumentDeliveryTest.kt index cd64913..acd02e5 100644 --- a/app/src/test/kotlin/top/yeij/cyrene/domain/chat/DocumentDeliveryTest.kt +++ b/app/src/test/kotlin/top/yeij/cyrene/domain/chat/DocumentDeliveryTest.kt @@ -10,7 +10,7 @@ import top.yeij.cyrene.data.api.dto.DocumentRefDto /** * 「该不该走文件」的判定矩阵与 `chat.documents` 载荷构造(纯函数)。 * - * **形状来源**:`02-前后端协同事项.md` **回执五**(契约 v0.59 尚未发布)—— + * **形状来源**:`02-前后端协同事项.md` **回执五**(契约 v0.59 已发布(api-client.md §1.2「文档存储与摄取契约」))—— * 「≤5 条」「只收服务端存储名」「文档一律走 REST」「WS 上行帧 4096 字节硬上限仍在」; * 数值另对齐后端实现与测试:`chat_documents.go` 的 `maxChatDocuments = 5`、 * `wsReadLimit = 4096`(契约 v0.56 明确记载)。 diff --git a/app/src/test/kotlin/top/yeij/cyrene/domain/chat/DocumentFailureTest.kt b/app/src/test/kotlin/top/yeij/cyrene/domain/chat/DocumentFailureTest.kt index ee4af44..db11553 100644 --- a/app/src/test/kotlin/top/yeij/cyrene/domain/chat/DocumentFailureTest.kt +++ b/app/src/test/kotlin/top/yeij/cyrene/domain/chat/DocumentFailureTest.kt @@ -9,7 +9,7 @@ import top.yeij.cyrene.data.api.CyreneException /** * 文档错误码 → 可分支失败类型的映射(纯函数)。 * - * **来源**:`02-前后端协同事项.md` **回执五**(契约 v0.59 尚未发布)§一 S1 的四个错误码表, + * **来源**:`02-前后端协同事项.md` **回执五**(契约 v0.59 已发布(api-client.md §1.2「文档存储与摄取契约」))§一 S1 的四个错误码表, * 另核过后端实现里的常量(`documents.go` 的 `documentUnsupportedCode` / * `documentTooLargeCode` / `documentNotFoundCode`、`chat_documents.go` 的 * `tooManyDocumentsCode` / `documentsUnavailableCode`)。文案一律用**服务端产出的原文**,