@mokuyoaxis/dsh-iris 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,38 @@
6
6
 
7
7
  当前没有尚未发布的用户可见变更。
8
8
 
9
+ ## [0.1.3] - 2026-09-08
10
+
11
+ ### Added
12
+
13
+ - 新增公开的 Task/Attempt v2 语义契约,以及零网络纯函数真值表;冻结受理、自动 failover、观察、取消、产物交付、旧状态兼容和移动端用户状态的不可违反规则。
14
+
15
+ - 新增最小 Provider 提交契约、脱敏错误分类、写前持久化 Hook、零网络 Fake Provider 和旧任务纯规范化器;普通提交异常默认归为受理未知,只有明确 `not_accepted` 才能自动切换候选。
16
+
17
+ - 新增 Task v2 复制落盘与单调 revision 原语,并覆盖图片、视频、转写和 TTS:一次用户请求只创建一个 Task,每次候选在 HTTP 请求前写入 Attempt;视频和转写进一步区分上传与提交 stage。明确 4xx 拒绝才允许 failover,5xx、网络异常及缺失必要响应会以受理未知停止。
18
+
19
+ - 新增图片故障注入测试,覆盖 429 后异步/同步混合候选安全切换、500/网络失败/缺远端 ID 后零重复提交、API Key 不落任务文件、同步与异步生成成功后交付失败不重新生成、未知取消及提交中断恢复。
20
+
21
+ - 图片、视频、转写和 TTS Agent 工具开始读取 v2 事实轴:交付失败会明确表述为“生成成功但交付失败”,受理或结果未知会停止等待并要求人工确认。
22
+
23
+ - 新增 Task v2 运行时故障矩阵,覆盖盯守超时、连续轮询异常、远端明确失败、重启恢复、供应商缺失、交付中断、SSE 慢消费者和人工接管;全部使用本地 Fake/fixture,不发送计费请求。
24
+
25
+ - 新增无需安装或启动 DSH 的离线 `doctor()`、`dsh-iris doctor` CLI 与 `--json` 输出;检查运行时、依赖、私有存储、配置、模型、任务、临时文件和产物,使用稳定的 0/1/2 退出码。
26
+
27
+ - 新增公开架构、安全边界和故障注入矩阵文档。
28
+
29
+ ### Changed
30
+
31
+ - 将 v0.1.3 聚焦为“防重复计费与事实可信”:离线 Doctor v0 与最薄 CLI 保留在本版,完整 Host Adapter、Provider conformance 和依赖 DSH 运行时的 Doctor 扩展顺延到 0.1.4。
32
+
33
+ - 工作台、泡泡和任务详情开始消费 v2 派生用户态:排队/运行仍属于活动任务,观察暂停、受理或结果未知、生成成功但交付失败进入独立“需要处理”分区;旧任务继续按原四态显示。
34
+
35
+ - 状态快照新增进程 epoch 与单调 revision,客户端拒绝迟到快照;SSE 对慢消费者只保留最新待发状态。
36
+
37
+ - 任务详情新增重新观察、重新交付与知情重试:前两者禁止新生成提交;知情重试必须确认可能重复计费,并用新旧 Task 关系保留审计线索。
38
+
39
+ - 待处理任务新增“标为已读/恢复提醒”;知情重试创建新任务后自动归档原提醒并展示关联,避免同一异常重复占用泡泡角标。只有明确的 Task v1 才显示“旧任务 · 只读”,热更新字段缺失不再误标新任务。
40
+
9
41
  ## [0.1.2] - 2026-09-06
10
42
 
11
43
  ### Changed
@@ -118,7 +150,8 @@
118
150
  - 上传采用流式限额、临时 `.part` 文件和原子落盘,失败时会清理未完成文件。
119
151
  - 修改状态的路由拒绝明确的跨站请求,媒体文件继续使用随机能力令牌访问。
120
152
 
121
- [Unreleased]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.1.2...HEAD
153
+ [Unreleased]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.1.3...HEAD
154
+ [0.1.3]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.1.2...v0.1.3
122
155
  [0.1.2]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.1.1...v0.1.2
123
156
  [0.1.1]: https://github.com/mokuyoaxis/dsh-iris/compare/v0.1.0...v0.1.1
124
157
  [0.1.0]: https://github.com/mokuyoaxis/dsh-iris/releases/tag/v0.1.0
package/README.en.md CHANGED
@@ -105,7 +105,7 @@ dsh-iris ships as a native DSH plugin with a server side and a web client. The s
105
105
 
106
106
  Automated tests currently cover plugin loading, tool registration, client seats, and routing behavior. Version 0.1.1 completed host smoke tests on Linux ARM64 — in both a clean and a real web profile — against DSH `0.1.2-rc.1` on Node.js `22.23.2`: the browser startup graph, the full combined bundle, the Iris client factory, and the three UI seats present at that time were verified. The fourth prompt-optimizer seat added in 0.1.2 has now been rendered in a live Android browser; configuration loading, a real session-model optimization with thinking actually `off`, preview write-back, independent disabling and re-enabling, and the loop from a short draft to a succeeded image-generation task are verified. Browser-side cancellation and JSON operations have automated HTTP/configuration coverage; a step-by-step live-device record is still pending. Iris itself keeps Node.js `>=20.10` as its own floor.
107
107
 
108
- Iris 0.1.1–0.1.2 explicitly supports DSH `>=0.1.2-rc.1 <0.1.3-0` and no longer works with the legacy client runtime of DSH 0.1.0/0.1.1. DSH is still evolving quickly; later preview versions must pass verification before the supported range widens, and the compatibility badge is not an official certification. If DSH requires a newer Node.js, DSH wins.
108
+ Iris 0.1.1–0.1.3 explicitly supports DSH `>=0.1.2-rc.1 <0.1.3-0` and no longer works with the legacy client runtime of DSH 0.1.0/0.1.1. DSH is still evolving quickly; later preview versions must pass verification before the supported range widens, and the compatibility badge is not an official certification. If DSH requires a newer Node.js, DSH wins.
109
109
 
110
110
  ## Tools
111
111
 
@@ -158,12 +158,25 @@ By default, the optimizer uses the model selected for the current session and fa
158
158
 
159
159
  Capability assignment uses `providerId::modelId` as the model identity. The same model name from a different provider or account counts as two independent options.
160
160
 
161
- Generation capabilities accept multiple candidate models. Iris only tries the next candidate when the upload, the submission, or a synchronous generation fails; once a remote service has accepted a task, Iris never resubmits it automatically — that is how duplicate tasks and double billing are avoided. Accepted asynchronous tasks remain under the task system's watch.
161
+ Generation capabilities accept multiple candidate models. Iris tries the next candidate only when the provider explicitly proves that the request was not accepted. A 500 response, timeout, disconnect, missing response, polling failure, or local persistence failure never authorizes automatic resubmission. Once accepted, Iris may only resume observation or delivery.
162
+
163
+ The workbench lists paused observation, unknown acceptance/outcome, and successful generation with failed delivery under “Needs attention.” Re-observe never submits; re-deliver never regenerates; acknowledge/restore only changes the local reminder queue; only an explicitly confirmed informed retry creates a linked new task and may incur duplicate charges. Creating that task archives the original reminder while preserving its unknown facts and audit link. See [Task semantics](docs/TASK_SEMANTICS.md), [Architecture](docs/ARCHITECTURE.md), [Security](docs/SECURITY.md), and the [Fault-injection matrix](docs/FAULT_INJECTION.md).
162
164
 
163
165
  ![Task lifecycle and acceptance boundary](docs/assets/diagrams/iris-task-lifecycle.png)
164
166
 
165
167
  Transcription is a separate `transcribe` capability and does not consume the TTS or vision model configuration.
166
168
 
169
+ ## Offline diagnostics
170
+
171
+ No DSH installation or running host is required, and no provider request is sent:
172
+
173
+ ```bash
174
+ npx @mokuyoaxis/dsh-iris doctor
175
+ npx @mokuyoaxis/dsh-iris doctor --json
176
+ ```
177
+
178
+ The installed binary is `dsh-iris`. Exit code `0` is healthy, `1` means warnings, and `2` means hard errors. Doctor checks Node.js, sharp, ffmpeg/ffprobe, a real but cleaned-up storage write probe, configuration, models/assignments, task semantics, temporary files, and orphaned or missing artifacts. It cannot verify a running DSH host, browser service, or live provider.
179
+
167
180
  ## Composed workflow example
168
181
 
169
182
  Iris ships two agent skills (`iris-verify-ui` and `iris-compose-media`) that chain multiple tools into bounded, reviewable media workflows. The example below is "look → redraw → self-check": understand the source image first, then generate, review against concrete mismatches, and only deliver once the review passes.
@@ -239,6 +252,7 @@ Releases are triggered by `v*` tags through `.github/workflows/release.yml`: the
239
252
  - [Roadmap](docs/ROADMAP.md) (Chinese)
240
253
  - [File access across environments](docs/file-access-across-environments.md) (Chinese)
241
254
  - [Android 16 screenshot gallery](docs/screenshots.md)
255
+ - [Task/Attempt v2 semantics (Chinese)](docs/TASK_SEMANTICS.md)
242
256
 
243
257
  ## License
244
258
 
package/README.md CHANGED
@@ -105,7 +105,7 @@ dsh-iris 按 DeepSeek Harness 插件形态提供服务端与 Web 客户端入口
105
105
 
106
106
  当前自动化测试覆盖插件装载、工具注册、客户端槽位和路由行为。0.1.1 已在 Linux ARM64 的干净与真实 Web profile 中,使用 DSH `0.1.2-rc.1`、Node.js `22.23.2` 完成宿主烟测;浏览器启动图、完整组合 bundle、Iris 客户端工厂和当时的三个 UI 座位均已验证。0.1.2 新增的第四个提示词优化座位已在 Android 浏览器真机确认渲染,配置读取、真实会话模型优化(实际 thinking `off`)、预览写回、独立关闭与重新启用,以及从短草稿到图片生成任务成功的闭环均已验证;浏览器端取消和 JSON 操作已有自动化 HTTP/配置覆盖,尚待补充真机逐项记录。Iris 自身仍以 Node.js `>=20.10` 为最低基线。
107
107
 
108
- Iris 0.1.1–0.1.2 明确支持 DSH `>=0.1.2-rc.1 <0.1.3-0`,不再兼容 0.1.0/0.1.1 的旧客户端 Runtime。DSH 仍在快速演进,后续预览版须经验证后再扩大范围;兼容徽章不代表官方认证。若 DSH 要求更高 Node 版本,以 DSH 为准。
108
+ Iris 0.1.1–0.1.3 明确支持 DSH `>=0.1.2-rc.1 <0.1.3-0`,不再兼容 0.1.0/0.1.1 的旧客户端 Runtime。DSH 仍在快速演进,后续预览版须经验证后再扩大范围;兼容徽章不代表官方认证。若 DSH 要求更高 Node 版本,以 DSH 为准。
109
109
 
110
110
  ## 工具
111
111
 
@@ -158,12 +158,25 @@ Iris 会在 DSH 对话输入区提供一个无边框、无文字的“🫧”入
158
158
 
159
159
  能力分配使用 `providerId::modelId` 作为模型身份。同名模型如果来自不同供应商或不同账号,会被视为两个独立选项。
160
160
 
161
- 生成类能力可以配置多个候选模型。Iris 只会在上传、提交或同步生成阶段失败时尝试下一个候选项;远端服务一旦受理任务,就不会自动重新提交,以免产生重复任务或重复计费。已经受理的异步任务由任务系统继续跟踪。
161
+ 生成类能力可以配置多个候选模型。Iris 只有在供应商明确证明未受理时才会尝试下一个候选;500、超时、断网、响应缺失、轮询失败和本地落盘失败都不会授权自动重提。远端服务一旦受理任务,Iris 只会恢复观察或交付,以免产生重复任务或重复计费。
162
+
163
+ 工作台把观察暂停、受理/结果未知和生成成功但交付失败单列为“需要处理”。“重新观察”不会提交;“重新交付”不会重新生成;“标为已读/恢复提醒”只改变本地提醒队列;只有“知情重试”会创建新任务,并要求用户逐次确认潜在重复费用。新任务创建后,原提醒自动归档但保留未知事实和新旧任务关联。任务语义、架构、安全边界与故障证据分别见 [`TASK_SEMANTICS.md`](docs/TASK_SEMANTICS.md)、[`ARCHITECTURE.md`](docs/ARCHITECTURE.md)、[`SECURITY.md`](docs/SECURITY.md) 和 [`FAULT_INJECTION.md`](docs/FAULT_INJECTION.md)。
162
164
 
163
165
  ![生成任务生命周期与受理边界](docs/assets/diagrams/iris-task-lifecycle.png)
164
166
 
165
167
  转写是独立的 `transcribe` 能力,不会占用 TTS 或视觉能力的模型配置。
166
168
 
169
+ ## 离线诊断
170
+
171
+ 无需安装或启动 DSH,也不会发送供应商请求:
172
+
173
+ ```bash
174
+ npx @mokuyoaxis/dsh-iris doctor
175
+ npx @mokuyoaxis/dsh-iris doctor --json
176
+ ```
177
+
178
+ 安装后的二进制名是 `dsh-iris`。退出码 `0` 表示正常、`1` 表示有警告、`2` 表示有硬错误。Doctor 检查 Node、sharp、ffmpeg/ffprobe、数据目录真实写入、配置、模型/分配、任务语义、临时文件和孤儿/缺失产物;它不会判断运行中的 DSH、浏览器或真实 Provider 是否在线。
179
+
167
180
  ## 组合工作流示例
168
181
 
169
182
  Iris 自带两个 Agent Skills(`iris-verify-ui` 与 `iris-compose-media`),把多个工具编排成有界、可复核的媒体工作流。下例是「看图 → 重绘 → 自检」:先理解原图,再生成,复核针对具体偏差,只有复核通过才交付。
@@ -239,6 +252,7 @@ Iris 自带两个 Agent Skills(`iris-verify-ui` 与 `iris-compose-media`),
239
252
  - [路线图](docs/ROADMAP.md)
240
253
  - [文件访问与跨环境](docs/file-access-across-environments.md)
241
254
  - [Android 16 真机截图画廊](docs/screenshots.md)
255
+ - [Task/Attempt v2 语义契约](docs/TASK_SEMANTICS.md)
242
256
 
243
257
  ## License
244
258
 
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import { doctor, formatDoctorReport } from '../lib/doctor.js';
3
+
4
+ function usage() {
5
+ return [
6
+ 'Usage: dsh-iris doctor [--json]',
7
+ '',
8
+ 'Runs offline diagnostics only. It does not start DSH or send provider requests.'
9
+ ].join('\n');
10
+ }
11
+
12
+ const args = process.argv.slice(2);
13
+ if (args.includes('--help') || args.includes('-h')) {
14
+ console.log(usage());
15
+ process.exitCode = 0;
16
+ } else if (args[0] !== 'doctor' || args.some((arg, index) => index > 0 && arg !== '--json')) {
17
+ console.error(usage());
18
+ process.exitCode = 2;
19
+ } else {
20
+ const report = await doctor();
21
+ console.log(args.includes('--json') ? JSON.stringify(report, null, 2) : formatDoctorReport(report));
22
+ process.exitCode = report.exitCode;
23
+ }
@@ -0,0 +1,81 @@
1
+ # Iris 架构与边界
2
+
3
+ 状态:v0.1.3 当前实现。本文描述已经存在的代码边界,不把 0.2+ 规划写成现成功能。
4
+
5
+ ## 当前形态
6
+
7
+ Iris 目前以 DeepSeek Harness 插件运行。DSH 提供 Agent 工具注册、会话附件、浏览器和 Web UI 插槽;Iris 自己负责供应商配置、媒体动作、可信任务、产物落盘、媒体授权路由和工作台投影。
8
+
9
+ ```text
10
+ DSH Host / Cordis
11
+ ├─ Agent tools ───────────────┐
12
+ ├─ Web slots / browser │
13
+ └─ attachment/session ports │
14
+ ▼
15
+ actions.runAction
16
+ ├─ provider adapters
17
+ ├─ Task / Attempt v2
18
+ ├─ media delivery
19
+ └─ vision / local media tools
20
+ │
21
+ ▼
22
+ $DSH_HOME/iris/v1
23
+ providers.json · tasks.json
24
+ outputs/ · uploads/
25
+ ```
26
+
27
+ `lib/index.js` 是 DSH Host Adapter 的当前集中入口;`lib/client.js` 只消费同源 API 与 DSH UI Slot。`lib/api.js` 是工作台 HTTP 投影,不是真相来源。Task 的持久事实由 `lib/tasks.js` 管理。
28
+
29
+ ## 已稳定的核心候选
30
+
31
+ | 模块 | 职责 | DSH 运行时依赖 |
32
+ |---|---|---:|
33
+ | `task-semantics.js` | Task v2 枚举、旧状态与用户状态派生、自洽校验 | 无 |
34
+ | `provider-contract.js` | 提交结果、受理边界、错误脱敏、候选调度 | 无 |
35
+ | `tasks.js` | Task/Attempt 持久化、观察、恢复与交付状态 | 无;数据根仍沿用 `DSH_HOME` |
36
+ | `doctor.js` | 零网络离线环境与数据诊断 | 无 |
37
+ | `actions.js` | GUI 与 Agent 共用动作 | 有宿主上下文参数,部分动作依赖 Browser/会话能力 |
38
+ | `index.js` | DSH 工具、路由、Skill 与生命周期注册 | 有 |
39
+ | `client.js` | DSH Web Slot、工作台、泡泡和提示词入口 | 有 |
40
+
41
+ 0.1.3 不声称已有完整独立 Core 或 Local Host Adapter。完整 Command Service、Host Port 接口和非 DSH 运行入口属于后续版本;本版先保证任务语义与离线 Doctor 不依赖 DSH 包即可执行。
42
+
43
+ ## Task、Attempt 与 Artifact
44
+
45
+ - 一个用户意图对应一个 Task;每个候选供应商调用对应一个稳定 Attempt。
46
+ - Attempt 必须在可能发送计费请求前落盘。只有明确 `not_accepted` 才允许自动 failover。
47
+ - 生成结果与本地交付是两类事实。生成成功后下载失败仍保持 `outcome=succeeded`。
48
+ - 当前 Artifact 仍由任务中的文件、媒体令牌和附件记录表示;正式 Artifact Manifest、内容哈希和谱系属于 0.2.0。
49
+ - 每次 v2 任务变更递增 Task `revision`;完整状态快照另带进程 `stateEpoch/stateRevision`,客户端拒绝同一 epoch 中迟到的旧快照。
50
+
51
+ 详细状态机见 [Task/Attempt v2 语义契约](TASK_SEMANTICS.md),故障证据见 [故障注入矩阵](FAULT_INJECTION.md)。
52
+
53
+ ## Provider 边界
54
+
55
+ 现有 DashScope 与 OpenAI Images 兼容分支仍位于 `adapters.js`,尚未宣称完整 Provider SDK。0.1.3 已冻结供应商提交所需的最小契约:复合模型身份、写前 Hook、四类提交结果、受理证据和安全错误。新增 Provider 不应绕过该契约直接在失败时切换候选。
56
+
57
+ 完整接口与 conformance runner 延后到 0.1.4+,见 [Provider 提交契约 v0](PROVIDER_SUBMISSION_CONTRACT.md)。
58
+
59
+ ## Host Port 清单
60
+
61
+ | 能力 | 当前来源 | 缺失时行为 |
62
+ |---|---|---|
63
+ | 工具注册与 Fiber 生命周期 | DSH `ctx.tools` / `ctx.effect` | 对应工具不注册;其余能力继续装载 |
64
+ | Web 路由 | DSH `webServer` 或 `httpServer` | 工作台 API、媒体链接和 HTML 渲染不可用 |
65
+ | UI Slot | DSH Web Client | 不影响 Host 侧任务与离线 Doctor |
66
+ | Browser | DSH browser service | 仅 HTML 截图不可用 |
67
+ | 会话附件与输入草稿 | DSH session/input ports | 退化为 Iris 自有产物或浏览器上传 |
68
+ | Skills registry | DSH skills service | 随包 Skill 不自动注册;核心动作仍可用 |
69
+
70
+ 这些依赖目前由 `index.js` 的可选注入和守卫集中处理。0.1.4 将把它们转成正式 Host Adapter 接口并增加 Local Host fixture。
71
+
72
+ ## 事件与 UI
73
+
74
+ 任务和配置写入会触发节流 SSE 快照。每份快照都有进程 epoch 与单调序号;慢消费者进入背压后只保留最新快照,重连仍通过持久化全量状态收敛。工作台只展示稳定人类状态,内部事实轴保留在 API 详情中供诊断和人工动作判断。
75
+
76
+ ## 非目标
77
+
78
+ - 不在 0.1.3 启动独立常驻服务或复制 DSH 聊天界面。
79
+ - 不迁移到 SQLite/JSONL,不破坏旧任务读取。
80
+ - 不新增 Gemini、Fal 或 Replicate 分支。
81
+ - 不把离线 Doctor 的成功等同于 DSH Host、浏览器或真实供应商已可用。
@@ -0,0 +1,26 @@
1
+ # v0.1.3 故障注入矩阵
2
+
3
+ 状态:本矩阵全部使用本地 fixture、Fake Provider、Mock Fetch 或临时目录,不发送真实供应商请求。
4
+
5
+ | 场景 | 预期事实 | 自动重复提交 | 证据 |
6
+ |---|---|---:|---|
7
+ | 请求前/上传前失败 | `not_accepted`;可以尝试下一候选 | 仅下一候选一次 | `provider-contract.mjs`、`generation-actions.mjs` |
8
+ | 上传成功、提交响应 500/丢失 | `acceptance=unknown` | 0 | `transcribe-task-acceptance-unknown.mjs`、`video-task-acceptance-unknown.mjs` |
9
+ | 图片 500、断网或缺远端 ID | `acceptance/outcome=unknown` | 0 | `image-task-acceptance-unknown.mjs` |
10
+ | 已受理后结果落盘失败 | 保留已受理结果并返回本地 persist 错误 | 0 | `provider-contract.mjs` |
11
+ | 已受理后轮询 429/500/超时 | `watchState=exhausted`、`outcome=unknown` | 0 | `task-runtime-faults-v2.mjs` |
12
+ | 供应商明确返回任务失败 | `outcome=failed` | 0 | `task-runtime-faults-v2.mjs` |
13
+ | 已成功但下载/本地写入失败 | `outcome=succeeded`、`deliveryState=failed` | 0 | `task-store-v2.mjs`、`image-task-mixed-v2.mjs` |
14
+ | 进程在 submitting 阶段退出 | 无受理证据时转为 unknown,禁止恢复提交 | 0 | `task-store-v2.mjs` |
15
+ | 进程在 accepted/running 阶段退出 | 只恢复观察;供应商缺失则 suspended | 0 | `task-runtime-faults-v2.mjs` |
16
+ | 已成功、交付中途退出 | 保留 succeeded,交付标 failed | 0 | `task-runtime-faults-v2.mjs` |
17
+ | 取消时无法确认远端结果 | `cancelState/outcome=unknown` | 0 | `task-store-v2.mjs`、`task-manual-recovery-v2.mjs` |
18
+ | tasks/config 截断或结构损坏 | 隔离原文件并保留证据 | 0 | `damage.mjs`、`doctor.mjs` |
19
+ | SSE 断开、重连、迟到快照、慢消费者 | 全量快照收敛;旧序号被拒绝;背压只保留最新 | 0 | `api.mjs`、`client.mjs` |
20
+ | 上传中断、过期文件与 `.part` 残留 | 临时文件清理;不影响正式产物 | 0 | `api.mjs` |
21
+ | 旧任务附件超出最近索引 | 从完整任务历史解析,不依赖最近 50 条 | 0 | `generation-actions.mjs` |
22
+ | 人工重新观察/重新交付 | 只轮询或下载,不提交 | 0 | `task-manual-recovery-v2.mjs` |
23
+ | 标为已读/恢复提醒 | 只写本地提醒审计元数据,不改变任务事实 | 0 | `task-manual-recovery-v2.mjs` |
24
+ | 用户知情人工重试 | 独立确认、建立新 Task 关系并归档原提醒 | 明确授权后 1 | `task-manual-recovery-v2.mjs` |
25
+
26
+ 矩阵的硬性规则是:只要已有 `accepted` 或 `unknown` 事实,任何自动路径的生成提交次数增量必须为 **0**。人工重试不属于自动恢复;它必须由用户逐次确认,并在数据中保留新旧 Task 的关系。
@@ -0,0 +1,60 @@
1
+ # Iris Provider 提交契约 v0
2
+
3
+ 状态:**v0.1.3 最小内部契约,已覆盖现有生成能力。** 图片、视频、转写与 TTS 均执行本契约;完整 discovery、poll、cancel、download conformance 留到 v0.1.4。
4
+
5
+ ## 提交结果
6
+
7
+ Provider `submit()` 必须返回以下四种结构之一:
8
+
9
+ ```js
10
+ { kind: 'completed', value }
11
+ { kind: 'accepted', remoteTaskId }
12
+ { kind: 'not_accepted', error }
13
+ { kind: 'acceptance_unknown', error }
14
+ ```
15
+
16
+ - `completed`:同步请求已成功完成,是明确受理证据。
17
+ - `accepted`:异步请求已受理,必须包含非空 `remoteTaskId`。
18
+ - `not_accepted`:有证据确认生成请求未被受理,是唯一允许自动切换候选的结果。
19
+ - `acceptance_unknown`:请求可能已到达供应商,但没有拿到受理证据;必须停止自动提交。
20
+
21
+ 适配器抛出的普通异常默认转换为 `acceptance_unknown`。只有显式携带 `acceptance: 'not_accepted'` 的结构化错误才允许 failover;`retryable`、429、500、timeout 或 network 等分类不能单独授权重新提交。
22
+
23
+ ## 写前与写后 Hook
24
+
25
+ 候选调度必须接收 `beforeAttempt`:
26
+
27
+ 1. 生成 Attempt 的 ordinal、Provider 与复合模型身份;
28
+ 2. 调用 `beforeAttempt` 原子持久化,并返回稳定、非空的 Attempt ID;Hook 不得覆盖候选身份;
29
+ 3. 只有 Hook 成功后才能调用 Provider;
30
+ 4. Provider 返回后用 `afterResult` 保存受理事实。
31
+
32
+ `beforeAttempt` 失败时供应商调用次数必须为 0。`afterResult` 失败时,无论供应商结果为何,都必须停止候选调度;若已经受理,受理事实不能因为本地落盘失败而被降级。
33
+
34
+ ## 安全错误记录
35
+
36
+ 可持久化错误只包含:
37
+
38
+ ```json
39
+ {
40
+ "stage": "submit",
41
+ "category": "network",
42
+ "acceptance": "unknown",
43
+ "retryable": true,
44
+ "httpStatus": 503,
45
+ "providerCode": "optional-safe-code",
46
+ "safeMessage": "redacted message"
47
+ }
48
+ ```
49
+
50
+ 错误 stage 固定为 `validate/prepare/upload/submit/response/poll/cancel/download/persist/emit`;category 固定为 `invalid_request/authentication/quota/rate_limit/network/timeout/aborted/provider/protocol/local_io/unknown`。
51
+
52
+ 错误记录不得包含 `cause`、stack、请求体、响应正文、API Key、Authorization、POSIX/Windows 私有绝对路径或签名 URL。调用方可以在当前进程中保留原始异常用于调试,但不得把它当作 Task/Attempt JSON 或事件载荷。
53
+
54
+ ## 当前接入边界
55
+
56
+ `lib/provider-contract.js`、Task v2 复制落盘原语和零网络 Fake Provider 已冻结本契约。完整图片能力现在都会在请求前写入 Attempt:DashScope 旧异步返回远端 ID 后进入观察;DashScope 新同步与 OpenAI Images 的成功响应记为 `completed/accepted`,随后独立推进本地产物交付。异步与同步候选可以在同一个 Task 中安全切换。
57
+
58
+ 429 等可证明未创建任务的明确 4xx 拒绝可进入下一候选;408、409、425、499、5xx、网络异常、超时和成功响应缺少必要结果一律停止并记录 `acceptance=unknown`。同步生成已经成功后,下载或落盘失败记录为 `outcome=succeeded / deliveryState=failed`,不会重新生成。
59
+
60
+ 视频、转写与 TTS 也已使用相同边界:视频和转写分别持久化 `prepare/upload/submit` stage,上传失败只表示生成请求未受理;TTS 同步成功则先记 `completed/accepted` 再交付音频。工作台已经消费稳定的人类状态,并提供重新观察、重新交付、提醒已读/恢复和需确认费用的知情重试;v0.1.4 再完成 discovery、poll、cancel、download 等完整 Provider conformance。
package/docs/ROADMAP.md CHANGED
@@ -32,9 +32,9 @@ dsh-iris 已具备媒体生成、视觉处理和任务管理主流程。长期
32
32
  - 增加 Linux/Windows 与 Node.js 20.10/22 CI 矩阵、发布前测试护栏,并以当前 DSH 预览版完成宿主烟测。
33
33
  - 核对打包清单,记录真实环境和未验证平台。
34
34
 
35
- ## 发布候选
35
+ ## 已完成:0.1.2
36
36
 
37
- ### 0.1.2:可见、可达与唯一身份
37
+ ### 可见、可达与唯一身份
38
38
 
39
39
  - 保留 npm 包名 `@mokuyoaxis/dsh-iris`,以 “Iris Media for DSH” 作为展示名,并使用唯一 Cordis 行 ID 避免与另一款 `dsh-iris` 同装冲突。
40
40
  - 插件启用时自动注册两项随包 Skill,不要求用户克隆仓库、切换 cwd 或修改默认 Skill 搜索目录。
@@ -45,12 +45,12 @@ dsh-iris 已具备媒体生成、视觉处理和任务管理主流程。长期
45
45
 
46
46
  ## 下一步
47
47
 
48
- ### 0.1.3:可信任务与适配边界
48
+ ### 当前发行候选 0.1.3:可信任务与适配边界
49
49
 
50
- - 区分提交未受理、已受理与受理未知,完善 Attempt、取消和恢复语义。
51
- - 用故障注入验证提交响应丢失、下载和落盘失败时不会重复提交。
52
- - 定义最小 Host/Provider Adapter 契约、conformance fixture 与 Core 依赖方向守卫。
53
- - 提供不发送计费请求的离线 `iris doctor`,并公开任务、安全与架构契约。
50
+ - 图片、视频、转写与 TTS 已区分未受理、已受理与受理未知,并使用一个 Task、多 Attempt、独立观察/交付/取消事实;规范见[Task/Attempt v2 语义契约](TASK_SEMANTICS.md)。
51
+ - 零网络故障矩阵已覆盖提交响应丢失、受理后持久化失败、轮询耗尽、取消未知、各阶段重启、下载/落盘、上传残留、SSE 慢消费者与人工接管;证据见[故障注入矩阵](FAULT_INJECTION.md)。
52
+ - 最小 Provider 提交契约和 Core 依赖守卫已冻结;完整 Host Adapter 和 Provider conformance 顺延到 0.1.4,避免把可靠性修复变成大重构。
53
+ - 离线 `doctor()`、`dsh-iris doctor [--json]`、[架构](ARCHITECTURE.md)与[安全边界](SECURITY.md)已经提供;依赖 DSH 运行时的扩展诊断顺延到 0.1.4。
54
54
  - 在具备稳定录制条件后补充真实短视频证据;不以伪造或不稳定链接阻塞 0.1.2。
55
55
 
56
56
  ### 0.2.0:独立 Core 与产物记录
@@ -75,7 +75,7 @@ dsh-iris 已具备媒体生成、视觉处理和任务管理主流程。长期
75
75
  - WSL、远程浏览器和容器部署应优先使用上传或会话附件,避免混淆浏览器路径与宿主路径。
76
76
  - HTML 截图运行在离线沙箱中,远程资源和页面脚本不可用。
77
77
  - 模型发现只能列出候选项,具体能力需要通过实际请求确认。
78
- - Node 测试调度器不依赖 Bash;原生 Windows/WSL 完整测试与 DSH 冒烟尚待验证,不因调度器改写而宣称已支持全部平台。
78
+ - Node 测试调度器不依赖 Bash,Linux/Windows × Node.js 20.10/22 自动化矩阵已经通过;原生 Windows/WSL 的 DSH 宿主实机冒烟仍待补充。
79
79
 
80
80
  ## 质量要求
81
81
 
@@ -0,0 +1,53 @@
1
+ # Iris 安全边界
2
+
3
+ 状态:v0.1.3 当前实现。安全目标是避免凭据泄露、路径越权、跨站写入和因错误重试造成重复计费;Iris 与 DSH 仍是本机同一信任域内的预览软件,不构成多租户安全边界。
4
+
5
+ ## 信任模型
6
+
7
+ - DSH Host、Iris 插件进程和 `$DSH_HOME` 当前属于同一操作系统用户。
8
+ - 浏览器工作台只通过 Iris 的同源 Host 路由访问数据;默认只接受回环 Host。显式 `IRIS_TRUSTED_HOSTS` 只扩展 Host 校验,不等于认证。
9
+ - API Key 只在 Host 侧配置与供应商请求中使用。工作台、状态 API、任务记录、错误和 Doctor 输出不得返回完整 Key。
10
+ - DSH 仍处于快速演进阶段。Iris 的兼容范围不是对 DSH 本身安全性或生产就绪度的背书。
11
+
12
+ ## 凭据与配置
13
+
14
+ 供应商凭据保存在 `$DSH_HOME/iris/v1/providers.json`。POSIX 上 Iris 创建的目录和文件分别使用 `0700` 与 `0600`,启动时会在不跟随符号链接的前提下收紧既有 Iris 树。Windows mode 不等同于 ACL,仍依赖当前用户目录和系统账户权限。
15
+
16
+ API、SSE 和 Doctor 只返回凭据存在性或掩码提示。Provider 错误会移除 Bearer token、常见 Key、签名查询参数、堆栈和私有绝对路径。不要把 `providers.json`、环境变量或含签名的临时 URL 上传到 Issue。
17
+
18
+ `ai-paint` 是维护者未公开的本地前身,不是用户依赖。Iris 只有在用户显式设置 `IRIS_IMPORT_WORKBENCH_CONFIG` 为绝对路径且自身配置为空时才做一次性导入,不扫描其他项目,也不回写来源文件。
19
+
20
+ ## 受理与费用安全
21
+
22
+ - 所有生成 Attempt 在网络副作用前落盘。
23
+ - 只有供应商明确证明未受理时才允许自动 failover。
24
+ - 500、超时、连接重置、响应丢失、轮询失败、事件失败和本地落盘失败都不能授权自动重提。
25
+ - “重新观察”只查询已有远端任务;“重新交付”只查询并下载已成功产物。
26
+ - “知情重试”必须单独确认可能重复任务或重复计费,并创建带 `retryOf/manualRetries` 关系的新 Task。创建后只归档原提醒,不改写原任务的未知事实;当前只对能从安全记录无损重建的文生图和文生视频开放,文件型输入和截断文本要求用户从原始输入重新发起。
27
+ - “标为已读/恢复提醒”只操作有界的本地 `attentionEvents` 审计元数据,不发送网络请求,也不把用户处置等同于供应商已经受理。
28
+ - Iris 当前没有凭空假设 DashScope 的远端取消协议。停止本地观察后若远端结果无法确认,状态保持 unknown。
29
+
30
+ ## 文件、上传与媒体访问
31
+
32
+ - 浏览器上传使用大小上限、随机文件名、`.part` 临时文件和完成后的原子改名;中断时清理临时文件,过期副本按 TTL 回收。
33
+ - 输出文件名由 Iris 生成或通过 `basename` 收口,API 不返回宿主绝对路径。
34
+ - 媒体播放链接使用随机能力令牌。令牌应视为临时访问凭据,不应发布到公网。
35
+ - 清理任务元数据默认不删除产物;删除孤儿产物需要独立确认。
36
+ - 符号链接不会被私有树权限收紧逻辑跟随。Doctor 会把 Iris 数据根为符号链接视为硬错误。
37
+
38
+ ## Web 与渲染
39
+
40
+ - 修改状态的路由拒绝明确跨站请求,并限制 JSON/上传 Body 大小。
41
+ - HTML 截图在离线沙箱中运行,不具备 Iris/宿主同源权限;远程资源和页面脚本不可用。
42
+ - SSE 使用同源连接、节流和背压合并;慢消费者只保留最新快照,避免积压历史状态。
43
+ - 如果把 DSH 通过 LAN、反向代理或隧道暴露,必须由部署者另加真正的认证、TLS、访问控制和来源限制。
44
+
45
+ ## 离线 Doctor
46
+
47
+ `dsh-iris doctor` 不启动 DSH,不发送供应商或计费请求,也不打印 API Key。它会在 Iris 数据目录或最近可写父目录创建一个随机小文件并立即删除,用于验证真实写权限。`--json` 与文本输出使用同一结果模型,退出码为:`0` 正常、`1` 有警告、`2` 有硬错误。
48
+
49
+ Doctor 不能证明 DSH 工具注册、浏览器、附件服务、客户端资源或真实 Provider 在线;这些属于后续 Host 扩展诊断。
50
+
51
+ ## 报告问题
52
+
53
+ 报告安全问题前请移除 API Key、Authorization、完整 `providers.json`、私有路径、媒体能力令牌和供应商签名 URL。建议提供版本、平台、Doctor 的脱敏输出、最小复现步骤及是否发生真实费用。
@@ -0,0 +1,147 @@
1
+ # Iris Task/Attempt v2 语义契约
2
+
3
+ 状态:**v0.1.3 已实现。** Task v2 已覆盖图片、视频、转写与 TTS,包括同步/异步、上传/提交、混合协议候选、工作台稳定用户态、状态流防倒退、重新观察、重新交付、提醒已读/恢复和知情人工重试。正式 Artifact Manifest、完整 Provider/Host Adapter 和宿主扩展诊断仍属于后续版本。
4
+
5
+ ## 1. 为什么需要 v2
6
+
7
+ 媒体生成可能在供应商侧产生费用。网络断开并不能证明请求没有被受理,轮询失败也不能证明远端任务失败,下载失败更不能抹掉已经成功的生成结果。Iris 必须分别记录“有没有提交”“供应商是否受理”“远端结果是什么”“是否仍在观察”“产物是否已取回”和“取消是否得到确认”。
8
+
9
+ 本契约使用以下规范词:**必须**表示不可违反的安全或事实约束;**应该**表示除非有记录充分的理由,否则需要遵守;**可以**表示可选行为。
10
+
11
+ ## 2. 核心对象
12
+
13
+ - **Task**:一次用户意图。无论尝试过多少供应商,一个用户请求只能创建一个 Task。
14
+ - **Attempt**:Task 针对一个 `providerId::modelId` 的一次提交尝试。Attempt 必须在可能发送计费请求前持久化。
15
+ - **受理证据**:远端任务 ID、同步成功响应,或供应商明确声明已受理的其他稳定标识。
16
+ - **观察**:对已受理远端任务进行轮询或恢复接管,不等同于再次提交。
17
+ - **交付**:把远端结果下载、校验并原子保存为 Iris 本地产物。
18
+
19
+ Task 与 Attempt 使用稳定 ID。Attempt 的 `model` 与 Task 的权威 `modelRef` 必须保存复合身份 `providerId::modelId`;迁移期 Task 仍可额外保留裸 `model` 供 v0.1.2 UI 读取,但新逻辑不得以该兼容字段判断模型身份。
20
+
21
+ ## 3. 正交状态
22
+
23
+ Task v2 至少包含以下事实轴;字段值采用可序列化的 snake_case 英文枚举:
24
+
25
+ | 字段 | 值 | 含义 |
26
+ |---|---|---|
27
+ | `phase` | `queued` · `submitting` · `accepted` · `running` · `terminal` | Iris 当前是否还会自动推进该任务 |
28
+ | `acceptance` | `none` · `not_accepted` · `accepted` · `unknown` | 当前/最终 Attempt 的远端受理事实 |
29
+ | `watchState` | `idle` · `active` · `suspended` · `exhausted` | Iris 是否仍在观察远端任务 |
30
+ | `outcome` | `none` · `succeeded` · `failed` · `canceled` · `unknown` | 远端生成或确定性本地动作的结果 |
31
+ | `deliveryState` | `none` · `pending` · `downloading` · `ready` · `failed` | 成功结果是否已经可靠落成本地产物 |
32
+ | `cancelState` | `none` · `requested` · `remote_confirmed` · `local_confirmed` · `unknown` | 取消请求及其确认边界 |
33
+
34
+ `status` 仅为旧消费者保留,不再是真相来源。新代码必须读取上述字段。
35
+
36
+ ### 3.1 旧 `status` 的保守派生
37
+
38
+ | v2 事实 | 旧 `status` |
39
+ |---|---|
40
+ | `outcome=succeeded` 且 `deliveryState=ready` | `succeeded` |
41
+ | `outcome=failed` | `failed` |
42
+ | `outcome=canceled` 且取消已由远端或确定性本地动作确认 | `canceled` |
43
+ | 其余,包括受理未知、观察耗尽和交付失败 | `running` |
44
+
45
+ 四态旧字段无法无损表达“需要人工处理”。派生时宁可保持非终态,也不得伪造失败、成功或取消。现代 UI 必须使用 v2 事实轴。
46
+
47
+ ## 4. 受理与自动 failover
48
+
49
+ 自动 failover 的许可只由受理事实决定:
50
+
51
+ | `acceptance` | 允许自动切换 Provider | 说明 |
52
+ |---|---:|---|
53
+ | `none` | 否 | 尚未形成最终分类,必须先收敛为明确状态 |
54
+ | `not_accepted` | 是 | 已确认计费/生成请求没有被供应商受理 |
55
+ | `accepted` | 否 | 已有受理证据,再次提交可能重复计费 |
56
+ | `unknown` | 否 | 请求可能已经被受理,必须保守停止 |
57
+
58
+ 以下信息都**不能**单独授权自动 failover:`retryable=true`、HTTP 429/500、超时、连接重置、JSON 解析失败、轮询失败、下载失败、本地持久化失败或事件发布失败。
59
+
60
+ ### 4.1 分类规则
61
+
62
+ - 本地参数校验失败、请求发送前明确中止,或供应商明确拒绝且确认未创建任务:`not_accepted`。
63
+ - 收到远端任务 ID、同步成功响应或等价证据:`accepted`。
64
+ - 请求可能已经离开本机,但响应在获得受理证据前丢失:`unknown`。
65
+ - 无法证明“未受理”时,必须选择 `unknown`,不得为了可用性猜测 `not_accepted`。
66
+
67
+ 如果供应商支持幂等键,Attempt 应记录并复用该键;幂等能力可以帮助查询或安全恢复,但在未经合约证明前,不能把“发了幂等键”等同于“可以随意重试”。
68
+
69
+ 最小 Provider 返回结构、写前/写后 Hook 和错误字段详见[Provider 提交契约 v0](PROVIDER_SUBMISSION_CONTRACT.md)。
70
+
71
+ ## 5. Attempt 写前记录
72
+
73
+ 每次 Attempt 必须在可能发送生成请求前至少保存:
74
+
75
+ ```json
76
+ {
77
+ "id": "attempt_...",
78
+ "ordinal": 1,
79
+ "providerId": "provider-a",
80
+ "model": "provider-a::model-a",
81
+ "acceptance": "none",
82
+ "stage": "preparing",
83
+ "idempotencyKey": "optional-provider-key",
84
+ "startedAt": "2026-09-06T00:00:00.000Z"
85
+ }
86
+ ```
87
+
88
+ 上传临时输入与提交生成任务必须是不同 stage。上传成功并不等于生成请求已受理;但上传、提交和响应解析的错误证据都必须保留为脱敏分类,而不是一段不可机读的字符串。
89
+
90
+ ## 6. 远端结果与产物交付
91
+
92
+ - 远端返回成功后立即记录 `outcome=succeeded`,然后进入 `deliveryState=pending/downloading`。
93
+ - 下载、校验或本地落盘失败时,保持 `outcome=succeeded`,写入 `deliveryState=failed`。
94
+ - 交付失败只允许重新下载/落盘,不允许重新生成。
95
+ - 只有本地产物完成原子落盘并可读后,才写 `deliveryState=ready`。
96
+ - 供应商明确返回生成失败时才写 `outcome=failed`。
97
+
98
+ ## 7. 观察、超时与恢复
99
+
100
+ - 单次或连续轮询失败只改变观察事实;不得据此写 `outcome=failed`。
101
+ - 达到本地盯守上限时写 `watchState=exhausted`,结果通常为 `outcome=unknown`。
102
+ - 插件关闭或进程退出导致观察停止时,应保留可恢复信息;重启只能恢复观察,不能重新提交已受理或受理未知的 Attempt。
103
+ - `accepted` 的异步 Attempt 若供应商配置暂不可用,应进入 `watchState=suspended` 并给出修复建议,不能伪造远端失败。
104
+ - `unknown` 且没有远端任务 ID 时,只能等待供应商查询能力、幂等查询或用户知情决策。
105
+
106
+ ## 8. 取消
107
+
108
+ - 用户请求取消时先写 `cancelState=requested`。
109
+ - 供应商明确确认取消后,写 `cancelState=remote_confirmed` 与 `outcome=canceled`。
110
+ - 纯本地、尚未产生远端副作用的动作确定停止后,可以写 `cancelState=local_confirmed` 与 `outcome=canceled`。
111
+ - 仅停止本地轮询不等于远端取消。
112
+ - 取消请求超时、断网、供应商不支持取消或结果无法确认时,写 `cancelState=unknown`;`outcome` 也不得伪造为 `canceled`。
113
+
114
+ ## 9. 错误与隐私
115
+
116
+ 结构化错误至少应区分 stage、category、HTTP 状态、供应商错误码、受理状态和可安全展示的信息。任务、Attempt、事件与日志不得保存 API Key、Authorization 头、完整请求体、私有绝对路径或带临时签名的结果 URL。
117
+
118
+ 错误是否“可重试”与是否“允许自动重新提交”是两个不同问题。前者描述技术性质,后者只能由 `acceptance=not_accepted` 授权。
119
+
120
+ ## 10. 事件与 UI
121
+
122
+ - 每次 Task v2 持久化变更得到单调递增的 Task `revision`。完整状态快照另带进程 `stateEpoch/stateRevision`;客户端拒绝同一 epoch 内迟到的旧快照,SSE 重连后以持久化全量快照收敛。
123
+ - SSE 慢消费者进入背压时只保留最新待发快照,避免旧状态排队造成内存增长或视觉倒退。
124
+ - UI 应把事实映射成“排队中、运行中、观察暂停、需要确认、结果待取回、已完成、明确失败、已取消”等人类状态,不应在手机界面直接堆叠所有内部字段。
125
+ - `acceptance=unknown`、`cancelState=unknown` 和 `deliveryState=failed` 必须提供明确的人工接管入口;任何可能再次计费的操作都需要单独确认。
126
+ - 提醒处置与任务事实正交:标为已读只把任务移出主动提醒队列,恢复提醒只重新开放该队列;两者都不得修改受理、观察、结果、交付或取消事实。
127
+ - 知情重试创建并关联新 Task 后,原提醒自动记录为“已通过重试处理”。原任务保留原始未知事实和审计记录,但不继续产生重复角标;用户可从历史详情恢复提醒。
128
+
129
+ ## 11. 兼容与迁移
130
+
131
+ - v0.1.x 只允许向现有 JSON 记录增加字段,不执行破坏性批量迁移,不顺带引入 SQLite/JSONL。
132
+ - 旧记录缺少 v2 字段时,由纯兼容规范化器生成内存视图:既有成功记录保留成功证据;转存失败映射为远端成功但交付失败;轮询失败、无远端 ID 的运行记录和旧取消记录映射到 `unknown`,不能猜测失败、未受理或远端已取消。
133
+ - 读取旧任务不应立即重写整个文件;只有真实更新发生时才按原子写规则保存扩展后的记录。
134
+ - 在 v2 UI 和消费者完成迁移前继续输出派生 `status`。
135
+
136
+ ## 12. 必须通过的故障证据
137
+
138
+ 故障注入至少覆盖:请求发送前失败、提交响应丢失、获得远端 ID 后本地落盘失败、轮询 429/500/超时、远端成功后下载失败、取消响应丢失,以及 `submitting/accepted/running` 阶段的进程退出与恢复。
139
+
140
+ 每个场景必须同时断言最终事实字段和供应商提交调用次数。对于 `accepted` 或 `unknown`,自动重复提交次数必须为 **0**。
141
+
142
+ ## 13. 本版非目标
143
+
144
+ - 不在语义冻结阶段重写全部任务存储或 UI。
145
+ - 不新增 Gemini、Fal、Replicate 等供应商分支。
146
+ - v0.1.3 包含零网络、可独立运行的离线 Doctor v0 与最薄 CLI;依赖 DSH `ctx` 的宿主扩展诊断、完整 Host Adapter 和 Artifact Manifest 不属于本版。
147
+ - 不用更多自动重试换取表面成功率。
@@ -0,0 +1,30 @@
1
+ ## Iris Media for DSH 0.1.3
2
+
3
+ Version 0.1.3 makes media tasks safer to recover and much harder to accidentally submit twice. It is a reliability release: no new media provider is added.
4
+
5
+ ### Highlights
6
+
7
+ - Introduces Task/Attempt v2 across image, video, transcription, and TTS generation. One user intent owns one Task, while provider/model candidates become auditable Attempts.
8
+ - Records every Attempt before a potentially billable request. Automatic failover is allowed only after an explicit `not_accepted` result; timeouts, 5xx responses, disconnects, missing responses, and local persistence failures stop conservatively.
9
+ - Separates remote generation outcome from local artifact delivery. A download or filesystem failure no longer rewrites a successful generation as failed.
10
+ - Adds stable workbench states for paused observation, unknown acceptance/outcome, and unavailable artifacts, with a dedicated “Needs attention” section on desktop and mobile.
11
+ - Adds re-observe and re-deliver controls that never submit a new generation request. Informed retry requires a separate duplicate-charge confirmation, creates a linked new Task, and archives the original reminder so it is not counted twice.
12
+ - Adds acknowledge/restore controls for attention items. Acknowledgement only changes local reminder metadata; it never rewrites unknown provider facts. Legacy read-only labels now require an explicit Task v1 marker, avoiding false labels during hot-update version skew.
13
+ - Adds process-scoped state epochs/revisions and SSE backpressure coalescing so delayed snapshots and slow clients cannot roll the UI backwards.
14
+ - Adds an offline, zero-network Doctor API and CLI: `dsh-iris doctor [--json]`, also available through `npx @mokuyoaxis/dsh-iris doctor`. Exit codes are 0 for healthy, 1 for warnings, and 2 for hard errors.
15
+ - Publishes architecture, security-boundary, provider-submission, task-semantics, and fault-injection documentation.
16
+
17
+ ### Safety notes
18
+
19
+ - Re-observe only polls an already accepted remote task.
20
+ - Re-deliver only queries and downloads an already successful result.
21
+ - Informed retry may duplicate a still-running remote job and may incur another charge. Iris requires explicit confirmation and currently exposes it only when the original text input can be reconstructed safely.
22
+ - The offline Doctor does not start DSH, contact providers, print API keys, or claim that browser/tool registration is healthy.
23
+
24
+ ### Compatibility
25
+
26
+ - DeepSeek Harness: `>=0.1.2-rc.1 <0.1.3-0`
27
+ - Node.js: `>=20.10.0`
28
+ - Package: `@mokuyoaxis/dsh-iris`
29
+
30
+ This release was developed and locally validated on Linux ARM64 under Android 16 Termux/PRoot Debian with DSH `0.1.2-rc.1`. Cross-platform CI results should be confirmed from the release commit before publishing.