Vyntek
规格机器视觉规格

工具最近输出与动态调试

www 工作副本 · M4(Arden · 2026-10-21 Asia/Shanghai)
双轨:本页已迁入 Vyntek www;mvdocs output-inspection 仍在线对照。
实现边界:对拍 tip e46c042 — toolflow/output_inspector.hpp 已有 IImageOutputInspector、OutputCollectionEventKind(SnapshotReplaced / EmptySnapshot / Unavailable / Evicted)、KeepLatest / ReleaseAfterRouting(NON-STABLE / STUB)。RunSession::GetOutput 空串 stub ≠ KeepLatest。toolflow/diagnostic.hpp 仍是编排码表,不是本页观察事件。观察不驱动 Run 写在头注;门禁未标验收。Arden 不改实现。可勾选薄摘见 test-contracts-tc-out.md。
关联:overview · camera-acquisition · session-lifecycle · image-model · 预览 http://127.0.0.1:8792

目标设计与 API 草案,尚未实施。总体边界和推进状态见设计概述。

编排权威见 toolflow.md。本文只负责最近输出与动态调试观察;不是执行依赖仓库,也永不驱动 Run(与显示只观察、不停编排一致,见 toolflow §7.4.3)。公开调试标识用 ToolId(公开 API / 文档 / UI 绑定不另立第二标识)。显示消费者见 image-display.md;托管绑定见 csharp-binding.md。

语言:下文 API 示意为 C++(可置于 vyntek::toolflow 观察面或宿主集成层)。示意、非已发布 ABI。交给 ImageDisplay 显示时经绑定层,见 examples.md。

Alive 拍板(T10):空成功集合必须发「空快照」事件(禁止静默无事件);快照不可用 → Unavailable;淘汰 → Evicted;失败保留上次成功输出;观察永不驱动 Run;对外标识 ToolId。

本文负责输出集合、KeepLatest、动态连接/订阅、集合级事件、历史及查看引用。最近输出是观察状态,不是 ToolFlow 执行依赖仓库。

关联:ToolFlow(编排) · 头文件 · C# 适配 · 稳定发布 · SDK · 停止 · 显示 · 验证 · 测试契约薄摘 TC-OUT-*(全文仍 mvdocs test-contracts)

AddOwned 转移的是一个 handle 的所有权,不禁止图像被其他持有者访问。工具若交出后仍需读取,可事先保留独立的稳定 Share,并承担替换及关闭责任。调试器不借用队列拥有的对象,也不要求工具字段永久保留图像;编排运行时提供独立的工具输出存储,调试连接只读取这份状态。

必须分开三种生命周期:

对象生命周期职责
本次调用的输出收集器一次工具调用暂存 0~N 输出,成功后路由,失败时清理
工具最近输出存储可检查的流程会话按保留策略保存最近成功调用的输出集合,与有没有调试器连接无关
调试订阅与查看者动态连接到关闭接收变化标识,按需打开独立稳定引用,关闭时结束自己的保留
工具成功完成输出集合
       ├─ 由 ToolFlow 链接赋值交给下游输入(非 DAG/图边调度;观察层不路由执行)
       └─ 按会话策略更新最近输出存储(仅观察)→ 发集合级事件
                         ↓
              调试器随时连接、打开或断开(不触发 Run)

最近输出保留策略

支持动态查看当前结果的编辑/调试会话默认 KeepLatest,按工具保存最近一次成功调用的完整输出集合;即使调试器尚未连接,也维护该状态。纯生产会话可以显式选择 ReleaseAfterRouting,仅路由不保留,以减少内存与复制成本。保留策略是会话/端口配置,不是调试窗口是否打开的隐式副作用。

KeepLatest 的范围仍受每调用输出数量、保留字节和会话总预算约束,不保留所有历史。新调用输出集合准备成功后原子替换旧集合,旧引用释放;新调用成功但输出为空时更新为空,不能继续把上次非空结果标为当前输出。工具失败可保留上次成功结果,但必须带其真实运行/调用身份,与最新执行失败状态区分。

所有工具流输出都稳定只读,自有存储的最近结果通常直接 Share,不因调试另做像素复制,下游也不能改写它。相机 SDK 等外部缓冲默认复制到受配额管理的独立存储,避免每个工具的最近结果长期占用采集槽。保留策略由相机/会话集成声明,不能按格式或地址猜测;无法确认时采用独立快照。

需要脱离 SDK 时,输出存储作为消费者自行读取并复制;它与只读下游可以并行,但复制期间的原图引用仍须计量和保留。独立快照有新的 BufferId/Generation,条目另存来源版本作关联。路由层不替工具提交;ReleaseAfterRouting 不增加这项保留复制。若实现异步复制,完成与最近条目替换协调,过期复制不覆盖已更新结果。

保留配额不足或复制失败默认将该次结果标为快照不可用,不把业务工具改判失败,也不遗失待路由输出。要求“最近结果必须始终可检查”的会话须提前配置可容纳新旧替换峰值的预算,并采用明确背压/失败策略,不能在预算失败时默默展示旧结果冒充新结果。

集合级事件协议(T10 · Alive 拍板)

最近输出按调用级集合更新。订阅侧必须收到集合级变化,不能只用「存在图像项的 ImageOutputKey」冒充全集;空集合、不可用与淘汰均须显式事件。

事件种类(最小闭集)

种类何时发出语义
SnapshotReplaced成功调用且输出集合非空,原子替换为新集合当前可打开的最新成功集合身份已更新;可带 1~N 项 key 摘要或仅集合身份,由实现定
EmptySnapshot成功调用且输出集合为空必须发事件,禁止静默无事件、禁止继续把上次非空集合标为「当前」
Unavailable保留/复制失败、配额不足等导致该次快照不可检查业务工具仍可成功并完成路由;观察侧不得把旧成功集合冒充为本轮新结果
Evicted会话淘汰、预算回收或策略关闭导致已保留集合被清掉已打开的查看者句柄不受强制关闭,但新的 TryOpenLatest 对该身份返回不可用

另有约定(与上表同级、Alive 拍板):

  1. 失败保留上次成功输出:工具本次失败时,不替换最近成功集合;可另发执行失败状态(属 Run/Tool 状态面,非本表必发项)。观察者看到的「当前成功快照」仍指向上次成功身份,并与最新失败状态区分。
  2. 观察永不驱动 Run:订阅回调、TryOpen、重放均不得隐式触发 Run、链接赋值或重新采集;与显示只观察、不停编排一致。
  3. 对外标识用 ToolId:事件与 key 中的工具字段为 ToolId;公开 API / 文档 / UI 绑定不另立第二标识。

示意 C++(观察侧;UI 绑定另议)

// 示意、非已发布 ABI。观察面;不驱动 Run。
namespace vyntek::toolflow {

enum class OutputCollectionEventKind {
  SnapshotReplaced,  // 非空成功集合替换
  EmptySnapshot,     // 空成功集合(禁止静默)
  Unavailable,       // 快照不可用(配额/复制等)
  Evicted,           // 集合被淘汰
};

struct OutputCollectionEvent {
  OutputCollectionEventKind kind;
  RunId run_id;
  ToolId tool_id;              // 对外稳定标识
  InvocationId invocation_id;  // 与本次集合身份一致;失败保留时仍指向上次成功 invocation
  // 可选:port 范围摘要;EmptySnapshot / Evicted / Unavailable 可不带图像项
};

struct ImageOutputKey {
  RunId run_id;
  ToolId tool_id;
  InvocationId invocation_id;
  std::string port_name;
  int image_index;
};

class IImageOutputInspector {
 public:
  // 成功时 key 与 image 来自同一条目;image 是查看者拥有的稳定 Share(ReadOnly)
  bool TryOpenLatestOutput(
      RunId run_id, ToolId tool_id, std::string_view port_name, int image_index,
      ImageOutputKey& key, vyntek::imaging::PixelImageHandle& image);

  bool TryOpenOutput(const ImageOutputKey& key,
                     vyntek::imaging::PixelImageHandle& image);

  // 集合级通知;replay_latest 重放当前保留集合对应事件(含 EmptySnapshot)
  // 只通知标识/事件,不交接图像;回调在锁外执行
  OutputSubscription SubscribeCollectionEvents(
      std::function<void(const OutputCollectionEvent&)> observer,
      bool replay_latest = true);

  // 可选薄封装:仅当事件携带可打开项时转发 ImageOutputKey(不能代替集合事件)
  OutputSubscription SubscribeOutputs(
      std::function<void(const ImageOutputKey&)> observer,
      bool replay_latest = true);
};

}  // namespace vyntek::toolflow

禁止:用虚构的 image_index 表示空集合;用「无回调」表示空成功;在 Unavailable 时继续展示旧非空集合却不标身份过期;在观察回调里启动 Run。

验收要点见 validation-and-roadmap.md 阶段 E 与已拍板表 T10。可勾选契约见 test-contracts-tc-out.md TC-OUT-*(Arden · R9);场景骨架见 examples-scenarios.md S10。勿与 T15 开放风险 R9(编辑 UI)撞号。

动态连接与打开

调试缓存以运行、工具、调用、端口及项索引定位,不能仅按工具名、ImageId 或 BufferId。连续运行/重试中的同一工具会多次执行,一次调用也可产生多项共享 ROI。最新索引指向完整身份,不把观察索引用作跨运行的数据依赖。公开字段一律 ToolId。

建立订阅与取得当前快照索引必须协调,避免“先查询再订阅”丢掉中间更新;回调在锁外执行。连接后可立即打开已保留结果,并订阅后续结果,不要求暂停或重建流程。通知允许按工具/端口合并为最新标识,不能为每次采集积累带图像引用的无界事件队列。实际条目在通知后可能已淘汰,TryOpen 返回不可用是正常竞争结果,不返回已关闭对象;此时事件面应已或即将见到 Evicted / Unavailable。

打开与替换/淘汰原子协调:成功返回前已取得独立稳定引用,缓存关闭旧条目不会破坏打开的查看者。查看者自行 OpenRead,或经绑定层交给 ImageDisplay(C#);临时读取、查看者 handle 与控件访问分别关闭。调试器断开只释放订阅及它拥有的查看引用,不清空运行时最近输出,也不关闭算法或队列拥有的对象。重新连接仍可读取保留状态;重放须包含当前空快照事件(若当前为空)。

ReleaseAfterRouting 会话也允许运行中添加调试器,并从此启用选定工具的保留或观察后续输出;但是已经回收的过去结果无法补取。动态连接能力不等于无限历史恢复。需要即时查看上次结果时,必须事先采用 KeepLatest,或拥有其他明确保留者。

历史、失败与 SDK 退出

历史和断点固定项是最近输出之外的显式保留,分别限制数量、字节及期限。已打开查看者也计入保留成本;它们不会因缓存淘汰被强制关闭。固定项超限时拒绝继续保留或导出外部存储,不无限增长。调试修改通过 CloneAsync 创建独立图像,不修改业务输出。

若需查看失败调用的部分结果,可以保留已完成写入的暂存项并标为未提交/失败调用,不路由为成功输出,也不替换最近成功集合。观察失败不能改变业务所有权,输出收集器仍按工具结果正常清理。

SDK 场景默认在开放查看前形成独立快照,流程可归还采集槽。若显式选择共享观察,缓存复制或淘汰不关闭此前已打开的原图引用;停相机必须等待这些查看者、显示读取和 pin 退出。会话关闭释放其输出存储;若调试状态需要在运行结束后继续保留,显式移交到独立调试会话。导出的独立快照可继续查看,SDK 共享引用不能被伪装成已脱离。

实现对拍(tip e46c042 · 按实)

规格期望tip e46c042 现状
IImageOutputInspector / T10 事件闭集外形在 output_inspector.hpp(ImageOutputInspector);NON-STABLE
KeepLatest / ReleaseAfterRouting枚举 + 内存保留策略在;动态订阅重放 / 查看者寿命 未标验收
RunSession::GetOutput已实现标量投影(图像句柄无字符串形式故空串);≠ KeepLatest 保留集
toolflow/diagnostic.hpp编排 DiagnosticCode;≠ 本页观察事件
观察永不驱动 Run头注已写(M4-09);无门禁勾选
TC-OUT-01…09勾选仍空;无一标验收完成

显示打开最近输出见 image-display(M4-11 / M5)。


文档状态:www 工作副本(2026-10-21,Asia/Shanghai)。T10 集合事件已拍板。与 toolflow v1.9 §7.4.3、validation 已拍板表对齐;可勾选见 Arden · R9(TC-OUT- / S10)。对拍 tip e46c042。*

On this page