mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-14 04:01:35 +00:00
test(snapshot): bind sibling roles to catalog publication order
This commit is contained in:
+2
-2
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md
|
||||
2026-09-01-parent-owned-subagent-catalog.md: b0eee83499f8f9f3b3e2be652037dc882e005c94
|
||||
2026-09-01-parent-owned-subagent-catalog.zh.md: 8985eb291c5dbfadb53eb3576dcd9306496aa983
|
||||
2026-09-01-parent-owned-subagent-catalog.md: 24036545d72070e0c46dd4d6ac4ac30728140afd
|
||||
2026-09-01-parent-owned-subagent-catalog.zh.md: 416fba9fc75842b3b4a2a46c67568d232135cae2
|
||||
|
||||
@@ -24,6 +24,8 @@ The utility owns chunk layout and its shared capacity constant; the catalog owns
|
||||
|
||||
Fork isolation uses the exact `Session.inheritedEventCount` supplied to projection initialization. The fold ignores `subagent/catalog` events below that offset. The state stores the inherited offset but not each event seq because acceptance is decided during folding.
|
||||
|
||||
Headless snapshot collection assigns sibling fixture roles by their parent catalog order, regardless of child creation timestamps: provider startup can publish an older Session after a newer one. The collection preserves each log verbatim.
|
||||
|
||||
Snapshot normalizers zero `childCreatedAt` because it originates from the process clock. Event order and source-event references remain intact: adjacent facts can come from sequential creation, so adjacency does not establish commutativity.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
@@ -24,6 +24,8 @@ child header 与 `subagent/descriptor` 继续拥有恢复与 composition 权威
|
||||
|
||||
fork 隔离使用 projection 初始化时提供的精确 `Session.inheritedEventCount`。fold 忽略该 offset 之前的 `subagent/catalog` 事件。state 保存 inherited offset,但不保存每条 event seq,因为接受判定已在 fold 时完成。
|
||||
|
||||
Headless 快照采集按父目录顺序分配同父子级的 fixture 角色,不依赖子级创建时间戳:provider 启动可能在较新的 Session 之后发布较旧的 Session。采集过程原样保留每份日志。
|
||||
|
||||
snapshot normalizer 会把 `childCreatedAt` 归零,因为它来自 process clock。事件顺序与来源事件引用保持不变:相邻 fact 也可能来自顺序创建,因此相邻关系不能证明可交换性。
|
||||
|
||||
## 考虑过的替代方案
|
||||
|
||||
@@ -176,8 +176,8 @@ async function persistedSessions(cwd: string): Promise<SessionLog[]> {
|
||||
expect(assertPersistedSessionVersion(basename(file), content), `${file}: current writer`).toBe(SESSION_FORMAT_VERSION)
|
||||
return { content, header: headerOf(content) }
|
||||
}))
|
||||
// Same-millisecond siblings bind to fixture roles by their parent's recorded
|
||||
// discovery order; random persistence filenames do not identify child roles.
|
||||
// Siblings bind to fixture roles by catalog publication order; concurrent
|
||||
// provider startup can publish an older Session after a newer one.
|
||||
const catalogOrders = new Map(logs.map(log => [log.header.id, new Map(
|
||||
records(log.content)
|
||||
.filter(event => event.type === 'subagent/catalog')
|
||||
@@ -187,10 +187,12 @@ async function persistedSessions(cwd: string): Promise<SessionLog[]> {
|
||||
const leftChild = typeof left.header.parentSession === 'string'
|
||||
const rightChild = typeof right.header.parentSession === 'string'
|
||||
if (leftChild !== rightChild) return leftChild ? 1 : -1
|
||||
const timeOrder = Number(left.header.createdAt) - Number(right.header.createdAt)
|
||||
if (timeOrder !== 0 || left.header.parentSession !== right.header.parentSession) return timeOrder
|
||||
const catalogOrder = catalogOrders.get(left.header.parentSession)
|
||||
return (catalogOrder?.get(left.header.id) ?? Infinity) - (catalogOrder?.get(right.header.id) ?? Infinity)
|
||||
if (left.header.parentSession === right.header.parentSession) {
|
||||
const catalogOrder = catalogOrders.get(left.header.parentSession)
|
||||
const childOrder = (catalogOrder?.get(left.header.id) ?? Infinity) - (catalogOrder?.get(right.header.id) ?? Infinity)
|
||||
if (childOrder) return childOrder
|
||||
}
|
||||
return Number(left.header.createdAt) - Number(right.header.createdAt)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -782,6 +784,31 @@ describe('headless recorded-session snapshots', () => {
|
||||
expect(stderrFromSession(log)).toBe('dsh: reasoning:\nfirst thought\ndsh: reasoning:\nsecond\n')
|
||||
})
|
||||
|
||||
it.each([10, 20])('assigns sibling roles by catalog order when the first child timestamp is %i', async (firstCreatedAt) => {
|
||||
const cwd = await mkdtemp(join(tmpdir(), 'dsh-headless-catalog-order-'))
|
||||
try {
|
||||
const logs = [
|
||||
[
|
||||
{ type: 'session', version: 2, id: 'parent', createdAt: 1 },
|
||||
{ type: 'subagent/catalog', data: { childId: 'child-z' } },
|
||||
{ type: 'subagent/catalog', data: { childId: 'child-a' } },
|
||||
],
|
||||
[{ type: 'session', version: 2, id: 'child-z', createdAt: firstCreatedAt, parentSession: 'parent' }],
|
||||
[{ type: 'session', version: 2, id: 'child-a', createdAt: 10, parentSession: 'parent' }],
|
||||
].map(rows => rows.map(row => JSON.stringify(row)).join('\n') + '\n')
|
||||
for (const content of logs) {
|
||||
const directory = join(cwd, '.dsh', 'sessions', String(headerOf(content).id))
|
||||
await mkdir(directory, { recursive: true })
|
||||
await writeFile(join(directory, 'session.v2.jsonl'), content)
|
||||
}
|
||||
const actual = await persistedSessions(cwd)
|
||||
expect(actual.map(log => log.header.id)).toEqual(['parent', 'child-z', 'child-a'])
|
||||
expect(actual.map(log => log.content)).toEqual(logs)
|
||||
} finally {
|
||||
await rm(cwd, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('writes header sidecars without replacing a retained Session generation', async () => {
|
||||
const directory = await mkdtemp(join(tmpdir(), 'dsh-headless-sidecars-'))
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user