Documentation
¶
Overview ¶
otelmap.go —— 轨迹行 → OTel 属性的**契约表**(属性名 / 来源字段 / 取值域 / 基数上界)。
生命周期: Experimental(v0.33.0 定级)——本包仍会改、删、拆,不承诺任何 兼容,升级风险自负;定级理由见 api-lifecycle.yaml,分级规则见 docs/api-compat.md。
为什么单独一张表 ¶
otel.go 的映射函数回答「这一行导出去长什么样」,这张表回答「**宿主可以依赖什么**」。 分开是因为失效形态不同:映射写错会出可见的错值;契约缺失**不会报错**——宿主建看板时 只能自己猜字段名,于是同一个语义在 A 宿主叫 @turn_id@、在 B 宿主叫 @turn@,跨宿主的 看板与告警全部落空,而遥测数据照常上行。
判据:每一项都必须「有主」 ¶
判据在 @otelmap_test.go@,且是**双向**的:映射函数写出了表里没有的属性 ⇒ 红;表里列了 映射函数产不出的属性 ⇒ 也红(后者防的是「表变成了许愿池」)。另逐项判四件事:来源字段 非空、取值域写出、基数上界写出依据、属性名唯一。缺一即红。
Go 类型为什么进契约 ¶
取值域的形态写的是 **Go 类型名**(string / int64 / float64 / bool):宿主导出时按类型 选 OTel 属性类型,类型不符的属性在多数后端里**静默丢弃**(不报错、不告警),表现为 「数据看起来上行成功、看板上就是没有」。写成 Go 类型名让用例拿反射直接比对映射函数的 真实产物——这是「表」与「代码」之间唯一不会漂的对拍方式。
哪些字段不许进 metric label ¶
只有**本仓枚举得出、也给得出上界**的属性才允许作 metric label(@LabelSafe@ 蕴含 取值域是枚举、且 @Card.Max@ 不小于取值数)。理由不是洁癖:label 的代价是时序数按取值数 **乘**上去,一个无界 label 就能让指标后端按会话数膨胀。@session_id@ / @agent_slug@ 是 典型,列在 @ForbiddenLabels@ 里——而它们**根本不在 Row 上**:结构上装不进去,不靠纪律拦。
payload.go —— 事件载荷取值助手(轨迹投影层读载荷的唯一入口)。
载荷是 map[string]any,经 JSON 往返后整数是 float64——「只认 int64」的 取值面会在宿主的发布路径上整片失明。三个助手把「缺失 / 类型不符」的 归一口诀收在一处:字符串空串、整数 0、布尔 false(布尔读成 false 是 保守方向,但调用方仍应发规范的 bool)。
project_sideeffect.go —— 副作用行与快照行的**投影**(v0.33.0,issue #99)。
排障两问的轨迹面:「这个副作用到底施加了吗」(授予 / 施加 / 对账 / 裁决) 与「恢复点停在哪个序号」(快照提交)。单成文件是**重新分组**,不是拆行数: 副作用投影有自己的配对语义(幂等键配对、授予段→对账段接续、点观察), 与工具行的 call_id 配对、轮次/步骤的括号段是三套不同的账。
形态上是包级函数而不是 Projector 的方法:投影器的行为面按行族分组, 每族一组函数——「这个投影器支持哪些行」由 apply 的分发面回答, 不靠方法数堆在类型上。
Package trajectory 事件流 → 轨迹行的投影器(机制面)。
「这一轮到底发生了什么、每段花了多久」这件事,宿主此前只能自己从事件流里拼: 起止时刻靠猜,工具调用与结果按 call_id 手工配对,配对缺了没人知道。各宿主 各拼一套,于是同一个问题的答案会漂——尤其是**时长这一个数**:有人拿载荷 体积估、有人拿 token 数除、有人按事件时刻相减,三种口径混进同一张表, 谁也说不清哪一列是实测、哪一列是猜的。
本包把这件事收成一条机制面:**吃本仓 eventbus 的事件,产出轨迹行**。
三条纪律:
**实测与估算不得混同**(本包存在的核心理由)。行的时长**只有一个源**: 起止时刻相减。Row 里**不存**时长字段——时长是 Duration() 现算的。 于是「按载荷体积估一个时长」这件事**无处安放**:不是靠纪律约束,是 结构上装不进去。没有实测值就是没有实测值(Duration 返回 ok=false), 不拿 0 冒充「瞬时完成」,也不拿估算值填进实测字段。
**配对不完整要显形**。工具调用与结果按 call_id 配对;只有调用没有结果、 结果重复、结果没有对应调用、同号重复声明——四种缺口都进 Issues(), 不静默丢弃。
**未完成不是完成**。只有开始没有结束的行,状态是 open(未收口), 不是「时长 0 的已完成行」。Finalize() 把「不会再有新事件」落成显式事实, 未收口的行原样报出。
事件流是追加式的,故投影是**增量**的:先喂一半再喂后半,既有行被就地更新 (补上结束时刻、时长随之变成实测),而不是追加出第二条行。
边界:本包是机制面,不含任何宿主领域知识;**不做前端渲染**——各宿主技术栈 不同,轨迹行是数据不是视图(要文案就用 Options.Summarize 注入)。
Index ¶
Constants ¶
const ( // AttrRowID 行标识(与 Row.ID 同值)。 AttrRowID = "harness.trajectory.row_id" // AttrKind 行类目(turn / step / tool_call / tool_result)。 AttrKind = "harness.trajectory.kind" // AttrRowStatus 行的收口状态(open / closed / orphan)。 AttrRowStatus = "harness.trajectory.status" // AttrTurnSeq 所属轮次序号(1 起;轮次外的事件不写此项)。 AttrTurnSeq = "harness.turn.seq" // AttrStepID 所属环节号(仅带环节号的行)。 AttrStepID = "harness.step.id" // AttrToolName 工具名(仅工具行;**属性**而不是 span 名,见头注纪律 1)。 AttrToolName = "harness.tool.name" // AttrToolCallID 工具调用标识(配对键,宿主跨 span join 用)。 AttrToolCallID = "harness.tool.call_id" // AttrToolPairing 配对状态(paired / missing_result / duplicate_result / …)。 AttrToolPairing = "harness.tool.pairing" // AttrToolDupResults 重复结果计数(>0 才写)。 AttrToolDupResults = "harness.tool.duplicate_results" // AttrDurationMs 实测时长(毫秒,float64)。**仅实测时出现**(见头注纪律 2)。 AttrDurationMs = "harness.trajectory.duration_ms" // AttrSummary 行摘要(宿主可用 Options.Summarize 覆盖;空则不写)。 AttrSummary = "harness.trajectory.summary" // ── 副作用行(v0.33.0,issue #99)───────────────────────────── // 排障第一问「这个副作用到底施加了吗」的属性面。属性命名与既有三类同构: // 领域段(harness.sideeffect.*)+ 语义后缀。 // AttrSideEffectKey 幂等键(配对键:同 Key 的授予段 / 对账段 / 点观察聚合到 // 同一行标识下;宿主跨 span join 用)。无界标识——禁止作 metric label。 AttrSideEffectKey = "harness.sideeffect.key" // AttrSideEffectPhase 副作用阶段(granted / completed / abandoned / uncertain / // resolved_applied / resolved_cleared / replayed / contended)。 AttrSideEffectPhase = "harness.sideeffect.phase" // AttrSideEffectResource 目标资源标识(租约的独占单位)。无界——禁止作 metric label。 AttrSideEffectResource = "harness.sideeffect.resource" // AttrSideEffectFence 栅栏令牌(授予段 / 点行为观察到的代数;非授予段不写)。 AttrSideEffectFence = "harness.sideeffect.fence" // AttrSideEffectSafety 重试安全性声明(unknown / safe / unsafe,与 // sideeffect.RetrySafety.String() 逐字一致;空声明不写——沉默按最弱处理, // 属性面不替宿主补默认值)。 AttrSideEffectSafety = "harness.sideeffect.retry_safety" // ── 快照行(v0.33.0,issue #99)────────────────────────────── // 排障第二问「恢复点停在哪个序号」的属性面。 // AttrCheckpointRunID 编排运行标识(宿主分配的稳定标识)。无界——禁止作 metric label。 AttrCheckpointRunID = "harness.checkpoint.run_id" // AttrCheckpointSeq 快照序号(严格递增;0 不会出现——seq=0 的快照不是一次真实提交)。 AttrCheckpointSeq = "harness.checkpoint.seq" // AttrCheckpointStatus 快照的编排状态(取值域见 contract 的状态常量集; // 本包**引用**那份词表而不复制——契约表里用 Note 指过去,抄一份就是第二真相)。 AttrCheckpointStatus = "harness.checkpoint.status" )
OTel 属性名(本仓命名空间)。宿主据此建 dashboard 与告警;改名即破坏兼容。
const TraceBoundary = TracePerTurn
TraceBoundary 本仓选定的 trace 切分单位。
依据见 otel.go 头注「trace 边界」:选「轮」不是习惯,是因为 Row.ID 的唯一性 范围恰好是轮内——把边界挪到环节,标识唯一性与 trace 内唯一性就不再是同一个范围。
Variables ¶
var AttrSpecs = []AttrSpec{ { Name: AttrRowID, Source: "Row.ID", Domain: Domain{Kind: "string", Note: "行标识;形态由投影器决定(turn#N / step#N / tool#<call_id> / <kind>#-<seq>),唯一范围是轮内"}, Card: Cardinality{Why: "取值随行数增长(行数由事件流长度决定),本仓定不出上界"}, }, { Name: AttrKind, Source: "Row.Kind", Domain: Domain{Kind: "string", Values: []string{ string(KindTurn), string(KindStep), string(KindToolCall), string(KindToolResult), string(KindSideEffect), string(KindCheckpoint), }}, Card: Cardinality{Max: 6, Why: "Kind 词表固定六值(与 Span.Name 同一词表:新增类目必须同步这里与用例)"}, LabelSafe: true, }, { Name: AttrRowStatus, Source: "Row.Status", Domain: Domain{Kind: "string", Values: []string{ string(StatusOpen), string(StatusClosed), string(StatusOrphan), }}, Card: Cardinality{Max: 3, Why: "Status 词表固定三值"}, LabelSafe: true, }, { Name: AttrTurnSeq, Source: "Row.Turn", Domain: Domain{Kind: "int64", Note: "1 起的轮次序号;轮次外的事件(Turn 为 0)不写此项"}, Card: Cardinality{Why: "随会话轮数增长,本仓定不出上界"}, }, { Name: AttrStepID, Source: "Row.StepID(Row.HasStep 为真时才写:环节号 0 是合法值,不能靠零值判有无)", Domain: Domain{Kind: "int64", Note: "环节号,由调用方给定(uint64 全域)"}, Card: Cardinality{Why: "取值由调用方决定,本仓定不出上界"}, }, { Name: AttrToolName, Source: "Row.Tool(仅工具行)", Domain: Domain{Kind: "string", Note: "工具名,来自工具调用事件载荷"}, Card: Cardinality{Why: "取值数由宿主的工具目录规模决定,本仓看不到那个目录;宿主若要按工具聚合,应在 label 侧用自己的白名单收敛"}, }, { Name: AttrToolCallID, Source: "Row.CallID(仅工具行)", Domain: Domain{Kind: "string", Note: "配对键:一次工具调用一个值,宿主跨 span join 用"}, Card: Cardinality{Why: "调用次数无上界"}, }, { Name: AttrToolPairing, Source: "Row.Pairing(仅工具行,且不为 PairingNone)", Domain: Domain{Kind: "string", Values: []string{ string(PairingPaired), string(PairingMissingResult), string(PairingDuplicateResult), string(PairingUnpairedResult), string(PairingDuplicateCall), }}, Card: Cardinality{Max: 5, Why: "Pairing 词表五值(PairingNone 是「不适用」,不写进属性)"}, LabelSafe: true, }, { Name: AttrToolDupResults, Source: "Row.DupResults(仅工具行,且 >0)", Domain: Domain{Kind: "int64", Note: "重复结果计数,1 起;没有重复就没有这个属性"}, Card: Cardinality{Why: "重复次数无上界(正常情况下恒为 1)"}, }, { Name: AttrDurationMs, Source: "Row.Duration()(StartAt 与 EndAt 相减,不是单独存的字段)", Domain: Domain{Kind: "float64", Note: "实测毫秒;**仅实测时出现**——没有实测就没有这个属性,不写 0、不估一个"}, Card: Cardinality{Why: "连续值,本仓定不出上界"}, }, { Name: AttrSummary, Source: "Row.Summary(可由 Options.Summarize 覆盖)", Domain: Domain{Kind: "string", Note: "宿主注入的展示文案;内核默认标签不含任何领域词"}, Card: Cardinality{Why: "自由文本,本仓定不出上界"}, }, { Name: AttrSideEffectKey, Source: "Row.SideEffectKey(仅副作用行)", Domain: Domain{Kind: "string", Note: "幂等键:一个逻辑动作一个值(宿主构造,须稳定);同 Key 的授予段/对账段/点观察共用一个行标识,宿主跨 span join 用"}, Card: Cardinality{Why: "动作数无上界(随运行规模增长)"}, }, { Name: AttrSideEffectPhase, Source: "Row.SideEffectPhase(仅副作用行)", Domain: Domain{Kind: "string", Values: []string{ string(SideEffectGranted), string(SideEffectCompleted), string(SideEffectAbandoned), string(SideEffectUncertain), string(SideEffectResolvedApplied), string(SideEffectResolvedCleared), string(SideEffectReplayed), string(SideEffectContended), }}, Card: Cardinality{Max: 8, Why: "Phase 词表固定八值(授予/施加/放弃/转未知/裁决两态/两个点观察;与 sideeffect 的 Outcome 词表同源,新增须同步这里与用例)"}, LabelSafe: true, }, { Name: AttrSideEffectResource, Source: "Row.SideEffectResource(仅副作用行)", Domain: Domain{Kind: "string", Note: "目标资源标识:租约的独占单位(宿主定义)"}, Card: Cardinality{Why: "资源数由宿主的领域决定,本仓定不出上界"}, }, { Name: AttrSideEffectFence, Source: "Row.SideEffectFence(仅副作用行,且 >0;授予段与点行为才携带)", Domain: Domain{Kind: "int64", Note: "栅栏令牌:同一资源上单调递增的代数,由存储侧在原子操作里分配"}, Card: Cardinality{Why: "随接管次数增长,本仓定不出上界"}, }, { Name: AttrSideEffectSafety, Source: "Row.SideEffectSafety(仅副作用行,且非空——空声明不写,不替宿主补默认值)", Domain: Domain{Kind: "string", Values: []string{"unknown", "safe", "unsafe"}}, Card: Cardinality{Max: 3, Why: "与 sideeffect.RetrySafety 的 String() 逐字一致(unknown=未声明,沉默按最弱处理)"}, LabelSafe: true, }, { Name: AttrCheckpointRunID, Source: "Row.CheckpointRunID(仅快照行)", Domain: Domain{Kind: "string", Note: "编排运行标识(宿主分配,须稳定且可跨进程重建)"}, Card: Cardinality{Why: "运行数随宿主的编排规模增长,本仓定不出上界"}, }, { Name: AttrCheckpointSeq, Source: "Row.CheckpointSeq(仅快照行,且 >0——seq=0 的快照不是一次真实提交)", Domain: Domain{Kind: "int64", Note: "快照序号:同一 RunID 下严格递增(存储侧 CAS 判据)"}, Card: Cardinality{Why: "随步骤推进次数增长,本仓定不出上界"}, }, { Name: AttrCheckpointStatus, Source: "Row.CheckpointStatus(仅快照行,且非空)", Domain: Domain{Kind: "string", Note: "快照的编排状态:取值域**应当**是 contract 包的状态常量集(created/running/waiting_approval/succeeded/failed/cancelled/timed_out),但值由宿主写入快照——本仓保证不了宿主不写别的,故不列 Values、不标 label-safe(对宿主写面的保证不该由本包代签)"}, Card: Cardinality{Why: "词表本身七值,但写入面在宿主,本仓给不出可保证的上界"}, }, }
AttrSpecs 映射契约表(顺序 = otel.go 的常量声明顺序,便于逐行对读)。
var ForbiddenLabels = []ForbiddenLabel{
{
Name: "session_id",
Why: "一次会话一个取值:进 label 会让指标时序数按会话数膨胀,且会话标识是可关联标识——进了指标后端就等于把它变成长期可查询的面",
},
{
Name: "agent_slug",
Why: "取值数随部署的 agent 目录增长,本仓定不出上界;同一部署内它也更像维度而不是枚举",
},
{
Name: "payload",
Why: "事件载荷:自由文本、基数无界,且可能含未脱敏内容——映射面刻意不读它(见 otel.go 头注「映射面不含 payload」)",
},
}
ForbiddenLabels 禁区清单。
这三项都不在 Row 上——写在这里是给宿主的:它们看起来「很像维度」(也确实是有用的 关联键),但落进 metric label 就变成无界基数。要关联会话,用 trace_id(真相源在 @oekit/tracing@),那是**标识**不是维度。
Functions ¶
This section is empty.
Types ¶
type AttrSpec ¶
type AttrSpec struct {
// Name 属性名(必是 otel.go 里的某个 Attr* 常量,且全表不重复)。
Name string
// Source 来源字段:Row 上的哪一个字段(派生值写清怎么算出来的)。
Source string
// Domain 取值域。
Domain Domain
// Card 基数上界。
Card Cardinality
// LabelSafe 能否作为 metric label;为真必须「枚举取值 + 本仓给得出上界」。
LabelSafe bool
}
AttrSpec 一个属性的映射契约。
type Cardinality ¶
type Cardinality struct {
// Max 本仓能保证的取值上界;0 = 本仓定不出上界。
Max int
// Why 上界依据(Max 为 0 时写清为什么定不出)。
Why string
}
Cardinality 属性基数上界。
type Domain ¶
type Domain struct {
// Kind 取值形态,取 **Go 类型名**(string / int64 / float64 / bool)。
// 见头注「Go 类型为什么进契约」。
Kind string
// Values 枚举取值(按本仓词表顺序);空 = 非枚举。
Values []string
// Note 取值域说明。非枚举必写(枚举的取值域已由 Values 表达完整)。
Note string
}
Domain 属性取值域。
type ForbiddenLabel ¶
ForbiddenLabel 明确禁止作为 metric label 的语义(宿主不得自行补进 label)。
type Issue ¶
type Issue struct {
// Pairing 缺口类目(missing_result / duplicate_result / unpaired_result /
// duplicate_call)。
Pairing Pairing
// CallID 相关工具调用标识(无关联调用时为空)。
CallID string
// Seq 相关行的序号。
Seq int
}
Issue 配对缺口(可观测面):配对不完整时显式报出,不静默丢弃。
type Kind ¶
type Kind string
Kind 轨迹行的类目。
const ( // KindTurn 轮次行:一轮 turn 的起止(turn_started / turn_ended)。 KindTurn Kind = "turn" // KindStep 步骤行:一个环节的起止(step_started / step_finished)。 KindStep Kind = "step" // KindToolCall 工具调用行:调用时刻为起,配对到的结果时刻为止。 KindToolCall Kind = "tool_call" // KindToolResult 工具结果行:**只在结果没有对应调用时**出现—— // 配对缺口要显形,不能因为「没有调用行可挂」就把结果丢掉。 KindToolResult Kind = "tool_result" // KindSideEffect 副作用行(v0.33.0,issue #99):一次副作用动作的 // 授予 → 收口段(granted 起,completed/abandoned/uncertain 止), // 以及该 Key 的对账段(uncertain 起,resolved 止)。排障第一问 // 「这个副作用到底施加了吗」的答案面。 KindSideEffect Kind = "sideeffect" // KindCheckpoint 快照行(v0.33.0,issue #99):一次编排进度快照的成功落库 // (checkpoint_committed)。**点事件**:无括号段,落成孤儿行(只有终点的行) // ——没有实测时长就不写时长,不拿 0 冒充。排障第二问「恢复点停在哪个序号」 // 的答案面。 KindCheckpoint Kind = "checkpoint" )
type Options ¶
type Options struct {
// Summarize 摘要注入点:宿主自定义行标签(展示文案归宿主,内核不认识
// 任何领域词)。返回空串时沿用本包的通用标签;nil 时全程用通用标签。
//
// 只在行创建时调用一次——行的可读字段(类目、标识、工具名、时刻)在创建
// 后不再变化,故摘要不需要跟着配对状态刷新。
Summarize func(Row) string
}
Options 投影选项。
type Pairing ¶
type Pairing string
Pairing 工具调用与结果的配对状态(非工具行恒为 PairingNone)。
const ( // PairingNone 不适用(非工具行)。 PairingNone Pairing = "" // PairingPaired 调用与结果已配对:起止齐备,时长为实测。 PairingPaired Pairing = "paired" // PairingMissingResult 尚未观察到结果。可能仍在途;投影收口后仍如此, // 即确认为「等了也没等到」。 PairingMissingResult Pairing = "missing_result" // PairingDuplicateResult 同一 call_id 收到第二个及以后的结果。 PairingDuplicateResult Pairing = "duplicate_result" // PairingUnpairedResult 结果没有对应的调用。 PairingUnpairedResult Pairing = "unpaired_result" // PairingDuplicateCall 同一 call_id 收到第二个调用声明。 PairingDuplicateCall Pairing = "duplicate_call" )
type Projector ¶
type Projector struct {
// contains filtered or unexported fields
}
Projector 增量投影器:事件流 → 轨迹行。
并发安全:事件流可能由多个生产者投递,故 Apply 内部加锁。
func (*Projector) Apply ¶
Apply 投一条事件(增量投影)。
已经被投过的事件不会被重复计入:后续事件只会**更新**既有行(补结束时刻、 把配对状态从「未配对」改成「已配对」),不会追加出第二条行。
func (*Projector) Finalize ¶
Finalize 收口投影:把「不会再有新事件」落成显式事实。
返回仍未收口的行(未完成行)。这些行是 open 态:它们有起点、缺终点, 不是「时长 0 的已完成行」。工具调用行若此时仍无结果,会被记成 missing_result 缺口——到这一步才知道「等不到」是真的等不到。
不锁死投影器:宿主若继续投事件,投影照常更新,相应缺口也会被清掉。
type Row ¶
type Row struct {
// Seq 行序号(1 起,按创建顺序):宿主据此排序,投影内稳定。
Seq int
// Kind 行类目。
Kind Kind
// ID 行标识:轮次行 "turn#1";带环节号的步骤行 "step#7";
// 工具行 "tool#<call_id>";副作用行 "sideeffect#<key>"(同 Key 的多段
// ——授予段、对账段——共用一个标识:它们是同一个动作的先后两段);
// 快照行 "checkpoint#<run_id>#<seq>";无自然键的行用 "step#-<seq>" 形式兜底
// ("-" 前缀表示「这个标识是投影生成的,不是业务自然键」)。
// 格式的唯一生成点是 turnRowID / stepRowID / toolRowID / sideeffectRowID /
// checkpointRowID / seqID——otel 的父子关系复用同一组函数,另写一份格式
// 父子就会连不上。
ID string
// Turn 所属轮次序号(1 起);轮次之外的事件为 0。
Turn int
// HasStep 是否带环节号(环节号 0 是合法值,故用独立标志位表达「有没有」)。
HasStep bool
// StepID 所属环节号(HasStep 为真时有效)。
StepID uint64
// CallID 工具调用标识(仅工具行;配对键)。
CallID string
// Tool 工具名(仅工具行)。
Tool string
// SideEffectKey 幂等键(仅副作用行;同 Key 的授予段与对账段共用它配对)。
SideEffectKey string
// SideEffectPhase 副作用阶段(仅副作用行)。打开的授予段为 granted;
// 收口时写成终态(completed / abandoned / uncertain);对账段收口时写成
// resolved_applied / resolved_cleared;点行为 replayed / contended。
SideEffectPhase SideEffectPhase
// SideEffectResource 目标资源标识(仅副作用行;租约的独占单位)。
SideEffectResource string
// SideEffectFence 栅栏令牌(仅副作用行;授予段/点行为观察到的代数)。
SideEffectFence uint64
// SideEffectSafety 重试安全性声明(仅副作用行;取值域 unknown/safe/unsafe,
// 与 sideeffect.RetrySafety 的 String() 形态逐字一致)。
SideEffectSafety string
// CheckpointRunID 编排运行标识(仅快照行)。
CheckpointRunID string
// CheckpointSeq 快照序号(仅快照行;「恢复点停在哪个序号」的答案)。
CheckpointSeq uint64
// CheckpointStatus 快照的编排状态(仅快照行;取值域见 contract 的状态常量集,
// 本包不复制那份词表——引用而不是抄写,才不会漂出第二份真相)。
CheckpointStatus string
// StartAt 起始时刻(取自事件时刻;缺失时零值)。
StartAt time.Time
// EndAt 结束时刻(取自事件时刻;未收口时零值)。
EndAt time.Time
// Status 收口状态。
Status Status
// Pairing 配对状态(仅工具行)。
Pairing Pairing
// DupResults 重复结果计数(同一 call_id 收到第二个及以后的结果时累加)。
DupResults int
// Summary 行摘要(默认通用标签;宿主可用 Options.Summarize 覆盖)。
Summary string
}
Row 轨迹行:一轮 turn 里的一段有起止的过程。
行里**没有**时长字段——时长由 Duration() 从起止时刻现算(见包头纪律 1)。 存一个时长字段就会多出第二个真相:事件时刻与存下来的时长各说各话, 而估算值也就能混进同一个字段冒充实测。
type SideEffectPhase ¶ added in v0.34.0
type SideEffectPhase string
SideEffectPhase 副作用行所处的阶段(与 sideeffect 包的 Outcome / 生命周期词表对齐; 本包不 import sideeffect——投影层只吃事件载荷字符串,取值域在契约表里逐字声明, 两边的一致性由契约用例钉住)。
const ( // SideEffectGranted 闸已授予执行权,动作进行中(行打开,未收口)。 SideEffectGranted SideEffectPhase = "granted" // SideEffectCompleted 施加并记账成功(Complete 被接受)。 SideEffectCompleted SideEffectPhase = "completed" // SideEffectAbandoned 显式放弃:确定未生效,或下游按幂等键去重(可安全重试)。 SideEffectAbandoned SideEffectPhase = "abandoned" // SideEffectUncertain 结果未知:可能已生效。该行的授予段就此收口, // 同 Key 的对账段开启(等 resolved 收口;收不了口会在 Finalize 显形)。 SideEffectUncertain SideEffectPhase = "uncertain" // SideEffectResolvedApplied 对账裁决「已生效」:Key 记为已完成,后续取回结果。 SideEffectResolvedApplied SideEffectPhase = "resolved_applied" // SideEffectResolvedCleared 对账裁决「未生效」:未知标记清除,Key 重新可执行。 SideEffectResolvedCleared SideEffectPhase = "resolved_cleared" // SideEffectReplayed 点观察:动作早已完成,本次取回既有结果(无括号段, // 落成孤儿行——原动作发生在别的进程里,这里只有「观测到重放」这一刻)。 SideEffectReplayed SideEffectPhase = "replayed" // SideEffectContended 点观察:资源正被他人持有 / 该 Key 有未裁决尝试。 // 双 Worker 争用的证据面。 SideEffectContended SideEffectPhase = "contended" )
type Span ¶
type Span struct {
// Name span 名(低基数,取值域见 Kind)。
Name string
// ParentID 父 span 的行标识(与 Row.ID 同源,见头注「trace 边界」);
// 空 = 根,宿主应为它开一个新 trace。
ParentID string
// Status span 状态。
Status SpanStatus
// StartAt 起点(未收口时为零值,宿主导出时可自行取当前时刻)。
StartAt time.Time
// EndAt 终点(未收口时为零值)。
EndAt time.Time
// Attributes 属性表(键取本文件的 Attr* 常量,值是 string/int64/float64)。
Attributes map[string]any
}
Span 一行轨迹的 span 表达(不含 exporter 相关字段:那是投递侧的事)。
type SpanStatus ¶
type SpanStatus string
SpanStatus span 状态(OTel 的三值词表)。
const ( // SpanStatusUnset 未定:这一行还没收口,或「仍在等结果」。 // // 缺省就是这个——把未定硬记成 error 会让真正的事故淹在噪声里。 SpanStatusUnset SpanStatus = "unset" // SpanStatusOK 已完成且没有观察到问题。 SpanStatusOK SpanStatus = "ok" // SpanStatusError 观察到**发生过**的问题(不是「还没等到」)。 SpanStatusError SpanStatus = "error" )
type TraceGranularity ¶
type TraceGranularity string
TraceGranularity trace 的切分单位。
const ( // TracePerTurn 一轮 turn 一个 trace(**本仓选它**)。 TracePerTurn TraceGranularity = "turn" // TracePerStep 一个环节一个 trace(本仓不选:行标识只在轮内唯一, // 同号环节会在两个 trace 里撞同一个标识)。 TracePerStep TraceGranularity = "step" )