refactor(schedule): make absolute times explicit

This commit is contained in:
Tianyi Cui
2026-08-09 16:30:11 +08:00
parent 3d6498e91b
commit b7ec8429a9
109 changed files with 1248 additions and 3219 deletions

View File

@@ -22,10 +22,7 @@ import { MemoryStorageBackend } from '../../../storage/storage-domain/tests/help
let nextRpc = 1
function request<P>(payload: P): RpcRequest<P> {
return {
rpcId: RpcId(`workspace-${String(nextRpc++)}`),
payload: { timeZone: 'UTC', clientTimeZone: 'UTC', ...payload },
}
return { rpcId: RpcId(`workspace-${String(nextRpc++)}`), payload }
}
function expectOk<T>(response: RpcResponse<T>): T {
@@ -362,157 +359,6 @@ describe('session creation and Workspace membership', () => {
expectOk(await api.sessions.create(request({ workspaceId: created.workspaceId, sessionId })))
expect(expectOk(await api.workspace.list(request({}))).items[0]?.sessionIds).toEqual([sessionId])
})
it('canonicalizes the immutable Session zone and rejects identity conflicts', async () => {
const { api, ctx, workspaceRoot } = await harness()
const sessionId = SessionId('session-zone-identity')
const alias = 'US/Eastern'
const canonical = new Intl.DateTimeFormat('en-US', { timeZone: alias })
.resolvedOptions().timeZone
expectOk(await api.sessions.create(request({ sessionId, cwd: workspaceRoot, timeZone: alias })))
expect(ctx.agents.get(sessionId)?.session.header.timeZone).toBe(canonical)
expectOk(await api.sessions.create(request({ sessionId, cwd: workspaceRoot, timeZone: canonical })))
const conflict = await api.sessions.create(request({
sessionId,
cwd: workspaceRoot,
timeZone: 'Asia/Shanghai',
}))
expect(conflict.result).toMatchObject({
ok: false,
error: {
code: 'session-conflict',
details: {
sessionId,
requestedCwd: workspaceRoot,
requestedTimeZone: 'Asia/Shanghai',
existingTimeZone: canonical,
},
},
})
})
it('keeps a live headerless Session compatible without absorbing a request zone', async () => {
const { api, ctx, workspaceRoot } = await harness()
const session = ctx.sessions.create(SessionId('session-zone-headerless'), {
meta: { cwd: workspaceRoot },
})
ctx.agents.register(stubAgent(session))
expectOk(await api.sessions.create(request({
sessionId: session.id,
cwd: workspaceRoot,
timeZone: 'Asia/Shanghai',
})))
expect(session.header.timeZone).toBeUndefined()
})
it('serializes different-zone creates so the first immutable identity wins', async () => {
const { api, ctx, workspaceRoot } = await harness()
const sessionId = SessionId('session-zone-race')
const first = api.sessions.create(request({
sessionId,
cwd: workspaceRoot,
timeZone: 'UTC',
}))
const second = api.sessions.create(request({
sessionId,
cwd: workspaceRoot,
timeZone: 'Asia/Shanghai',
}))
const [firstResult, secondResult] = await Promise.all([first, second])
expect(firstResult.result).toMatchObject({ ok: true, value: { sessionId } })
expect(secondResult.result).toMatchObject({
ok: false,
error: { code: 'session-conflict', details: { existingTimeZone: 'UTC' } },
})
expect(ctx.agents.get(sessionId)?.session.header.timeZone).toBe('UTC')
})
it.each([
[undefined, null],
['', ''],
[' UTC', ' UTC'],
['CST', 'CST'],
['GMT', 'GMT'],
['+08:00', '+08:00'],
['Not/A_Real_Zone', 'Not/A_Real_Zone'],
] as const)('rejects invalid Session zone input %j before Agent creation', async (timeZone, value) => {
const { api, ctx } = await harness()
const invalidRequest = request({})
Object.assign(invalidRequest.payload, { timeZone })
const response = await api.sessions.create(invalidRequest)
expect(response.result).toMatchObject({
ok: false,
error: { code: 'invalid-time-zone', details: { field: 'timeZone', value } },
})
expect(ctx.agents.list()).toHaveLength(0)
})
it('binds each canonical client zone to its own queued or steering message source', async () => {
const { api, ctx } = await harness()
const sessionId = expectOk(await api.sessions.create(request({ timeZone: 'UTC' }))).sessionId
const agent = ctx.agents.get(sessionId)
if (agent === undefined) throw new Error('created Agent missing')
const followup = vi.spyOn(agent, 'followup')
const steer = vi.spyOn(agent, 'steer')
const alias = 'US/Eastern'
const canonical = new Intl.DateTimeFormat('en-US', { timeZone: alias })
.resolvedOptions().timeZone
expectOk(await api.sessions.prompt(request({
sessionId,
mode: 'queue',
content: [{ type: 'text', text: 'queue' }],
clientTimeZone: alias,
})))
expectOk(await api.sessions.prompt(request({
sessionId,
mode: 'steer',
content: [{ type: 'text', text: 'steer' }],
clientTimeZone: 'Asia/Shanghai',
})))
expect(followup.mock.calls[0]?.[0].source).toMatchObject({
kind: 'user',
clientTimeZone: canonical,
})
expect(steer.mock.calls[0]?.[0].source).toMatchObject({
kind: 'user',
clientTimeZone: 'Asia/Shanghai',
})
})
it.each([undefined, '', 'CST', 'Not/A_Real_Zone'] as const)(
'rejects invalid prompt zone input %j before delivery',
async (clientTimeZone) => {
const { api, ctx } = await harness()
const sessionId = expectOk(await api.sessions.create(request({ timeZone: 'UTC' }))).sessionId
const agent = ctx.agents.get(sessionId)
if (agent === undefined) throw new Error('created Agent missing')
const followup = vi.spyOn(agent, 'followup')
const invalidRequest = request({
sessionId,
mode: 'queue' as const,
content: [{ type: 'text' as const, text: 'rejected' }],
})
Object.assign(invalidRequest.payload, { clientTimeZone })
const response = await api.sessions.prompt(invalidRequest)
expect(response.result).toMatchObject({
ok: false,
error: {
code: 'invalid-time-zone',
details: { field: 'clientTimeZone', value: clientTimeZone ?? null },
},
})
expect(followup).not.toHaveBeenCalled()
},
)
})
describe('Host Workspace increments', () => {