Skip to content

Commit 4e338c5

Browse files
author
SqlRush
committed
Accept sidechain timestamp aliases
1 parent b92a124 commit 4e338c5

5 files changed

Lines changed: 73 additions & 0 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ M6 补充:sidechain/subagent lifecycle 的 ID 等 string-like 字段现在接
152152

153153
M6 补充:sidechain runtime finish 现在会在写入 summary 前把 `success`/`error`/`canceled` 等状态别名归一为 `completed`/`failed`/`cancelled`,让 sidechain transcript 与主 transcript 的 lifecycle 输出保持 canonical。
154154

155+
M6 补充:sidechain lifecycle start/end time 现在接受 `startTimestamp`/`startTimestampMs`/`startedAtUnix` 以及 `endTimestamp`/`completedTimestamp`/`completedAtUnixMs` 等相邻时间别名,恢复第三方/旧 runtime transcript 时不再只依赖 `startedAt`/`endedAt`
156+
155157
M6 补充:sidechain agent metadata sidecar 读取现在接受 `type`/`subagentType`/`agentName`/`name``workspacePath`/`workspace`/`path`/`directory``taskDescription`/`prompt`/`input`/`command`/`title` 等字段别名,兼容历史或第三方生成的 subagent metadata。
156158

157159
M6 补充:transcript metadata loader 现在会按 `messageId` 建立 file-history snapshot 和 attribution snapshot 索引,并接受 `message_id`/`messageUuid`/`id` 等字段别名,和官方按消息恢复 snapshot 的语义对齐。

docs/claude-code-go-rewrite-plan.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ test/parity/ # golden tests against TS/official behavior
220220
- 本轮补充:remote history pagination 现在接受 `starting_after`/`startingAfter`/`after*` cursor aliases,page 字段和 link URL query 都可驱动下一页 `before_id` 续抓。
221221
- 本轮补充:remote history `SDKEvent` 本体接受 `eventType`/`event_type`/`role` 类型别名、`createdAt`/`created_at` 时间戳别名,以及 `payload`/`data`/`body`/`metadata`/`meta`/`attributes`/`properties`/`serializedMessage` message payload 别名;payload 只有 `role`/`content` 时也能 materialize 成 transcript message。
222222
- 本轮补充:sidechain lifecycle 读取现在接受运行时相邻字段别名,包括 `jobId`/`threadId`/`workflowId`/`operationId`/`requestId``workerType`/`taskType``workspaceRoot`/`projectPath``instructions`/`operationName`/`commandName`/`displayTitle``jobStatus``resultState``outputText` 和毫秒级 start/end time 字段,并会递归解包 `runtime`/`context`/`state` 容器。
223+
- 本轮补充:sidechain lifecycle start/end time 现在接受 `startTimestamp`/`startTimestampMs`/`startedAtUnix` 以及 `endTimestamp`/`completedTimestamp`/`completedAtUnixMs` 等相邻时间别名,恢复第三方/旧 runtime transcript 时不再只依赖 `startedAt`/`endedAt`
223224
- 本轮补充:sidechain lifecycle 和 metadata sidecar 的 task description/summary 读取现在接受 visible text payload,包括 text content block、message object、content block array、provider-style `message.content`/`parts`/`outputText` wrapper,并继续跳过 thinking/tool/image 等非可见块。
224225
- 本轮补充:transcript resume 的嵌套 content block 接受 `toolUseId`/`toolUseID``isError``cacheControl``cacheReference` 字段别名,并保留 cache edit 的 `cacheReference`
225226
- 本轮补充:transcript resume 的 nested content block `id`/`tool_use_id`/`toolUseId` 现在接受 JSON number,并保留为字符串 tool-use ID。

docs/first-second-parity-audit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ M6 progress now includes:
219219
- `internal/session`: sidechain lifecycle field extraction now also traverses collection wrappers such as `edges`, `nodes`, and `included`, plus array elements, so GraphQL connection or JSON:API included start/summary payloads can still recover state/list/resume fields.
220220
- `internal/session`: sidechain lifecycle scalar fields now accept JSON number values for IDs and other string-like fields, preserving numeric subagent IDs as strings across state/list/resume recovery.
221221
- `internal/session`: sidechain lifecycle and metadata sidecar loading now accept adjacent runtime aliases such as `jobId`, `threadId`, `workflowId`, `operationId`, `requestId`, `workerType`, `taskType`, `workspaceRoot`, `projectPath`, `instructions`, `operationName`, `commandName`, `displayTitle`, `jobStatus`, `resultState`, `outputText`, and millisecond start/end time fields under `runtime`/`context`/`state` or JSON:API/resource wrappers.
222+
- `internal/session`: sidechain lifecycle start/end time loading now also accepts timestamp and Unix-style aliases such as `startTimestamp`, `startTimestampMs`, `startedAtUnix`, `endTimestamp`, `completedTimestamp`, and `completedAtUnixMs`, preserving lifecycle times from adjacent runtime transcript writers.
222223
- `internal/session`: sidechain lifecycle and metadata sidecar summary/description loading now accepts visible text payloads, including text content blocks, message objects, content block arrays, and provider-style `message.content`/`parts`/`outputText` wrappers while ignoring hidden thinking/tool/image blocks.
223224
- `internal/session`: sidechain runtime finish now canonicalizes status aliases such as `success`, `error`, and `canceled` before writing summary records, keeping sidechain and main transcript lifecycle output stable.
224225
- `internal/session`: sidechain runtime now rejects duplicate starts while the same sidechain ID is running, and state loading treats a later start as a fresh lifecycle by clearing stale summary/end metadata.

internal/session/sidechain_status.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,19 @@ var sidechainLifecycleStartTimeFields = []string{
9191
"startedAt", "started_at",
9292
"startTime", "start_time",
9393
"startedTime", "started_time",
94+
"startTimestamp", "start_timestamp",
95+
"startedTimestamp", "started_timestamp",
9496
"createdAt", "created_at",
9597
"startedAtMs", "started_at_ms",
9698
"startTimeMs", "start_time_ms",
99+
"startTimestampMs", "start_timestamp_ms",
97100
"createdAtMs", "created_at_ms",
101+
"startedAtUnix", "started_at_unix",
102+
"startTimeUnix", "start_time_unix",
103+
"startTimestampUnix", "start_timestamp_unix",
104+
"startedAtUnixMs", "started_at_unix_ms",
105+
"startTimeUnixMs", "start_time_unix_ms",
106+
"startTimestampUnixMs", "start_timestamp_unix_ms",
98107
"timestamp", "time",
99108
}
100109

@@ -104,11 +113,25 @@ var sidechainLifecycleEndTimeFields = []string{
104113
"completedAt", "completed_at",
105114
"finishedAt", "finished_at",
106115
"stoppedAt", "stopped_at",
116+
"endTimestamp", "end_timestamp",
117+
"completedTimestamp", "completed_timestamp",
118+
"finishedTimestamp", "finished_timestamp",
107119
"endedAtMs", "ended_at_ms",
108120
"endTimeMs", "end_time_ms",
109121
"completedAtMs", "completed_at_ms",
110122
"finishedAtMs", "finished_at_ms",
111123
"stoppedAtMs", "stopped_at_ms",
124+
"endTimestampMs", "end_timestamp_ms",
125+
"completedTimestampMs", "completed_timestamp_ms",
126+
"finishedTimestampMs", "finished_timestamp_ms",
127+
"endedAtUnix", "ended_at_unix",
128+
"endTimeUnix", "end_time_unix",
129+
"completedAtUnix", "completed_at_unix",
130+
"finishedAtUnix", "finished_at_unix",
131+
"endedAtUnixMs", "ended_at_unix_ms",
132+
"endTimeUnixMs", "end_time_unix_ms",
133+
"completedAtUnixMs", "completed_at_unix_ms",
134+
"finishedAtUnixMs", "finished_at_unix_ms",
112135
"timestamp", "time",
113136
}
114137

internal/session/sidechain_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,52 @@ func TestLoadSidechainStateAcceptsAdjacentLifecycleSubtypeAliases(t *testing.T)
476476
}
477477
}
478478

479+
func TestLoadSidechainStateAcceptsTimestampAliases(t *testing.T) {
480+
sessionPath := filepath.Join(t.TempDir(), "session.jsonl")
481+
sessionID := contracts.ID("sess_1")
482+
if err := AppendSidechainMessage(sessionPath, sessionID, "timestamp-aliases", TranscriptMessage{
483+
Type: "system",
484+
UUID: "start_1",
485+
Timestamp: "2026-01-01T00:00:01Z",
486+
Subtype: "subagent_started",
487+
Content: map[string]any{
488+
"subagentId": "timestamp_worker",
489+
"startTimestampMs": int64(1710000000123),
490+
"status": "running",
491+
},
492+
}); err != nil {
493+
t.Fatal(err)
494+
}
495+
if err := AppendSidechainMessage(sessionPath, sessionID, "timestamp-aliases", TranscriptMessage{
496+
Type: "system",
497+
UUID: "summary_1",
498+
Timestamp: "2026-01-01T00:00:02Z",
499+
Subtype: "agent_finish",
500+
Content: map[string]any{
501+
"agentID": "timestamp_worker",
502+
"completedTimestamp": 1710000100,
503+
"completedTimestampMs": int64(1710000100456),
504+
"resultText": "timestamp aliases complete",
505+
},
506+
}); err != nil {
507+
t.Fatal(err)
508+
}
509+
510+
state, err := FindSidechainState(sessionPath, sessionID, "timestamp-aliases")
511+
if err != nil {
512+
t.Fatal(err)
513+
}
514+
if state.ID != "timestamp_worker" || state.Status != SidechainStatusCompleted || state.Summary != "timestamp aliases complete" {
515+
t.Fatalf("state = %#v", state)
516+
}
517+
if state.StartedAt != "1710000000123" {
518+
t.Fatalf("started at = %q", state.StartedAt)
519+
}
520+
if state.EndedAt != "1710000100" {
521+
t.Fatalf("ended at = %q", state.EndedAt)
522+
}
523+
}
524+
479525
func TestLoadSidechainStateAcceptsWrappedLifecycleContent(t *testing.T) {
480526
sessionPath := filepath.Join(t.TempDir(), "session.jsonl")
481527
sessionID := contracts.ID("sess_1")

0 commit comments

Comments
 (0)