test(goal): close the per-file coverage gaps for the goal surface
- projection.spec covers applyGoalProjection's non-message early return and the foreign-change-kind arm directly (the pure-function posture the unit requires — a throwing apply would tear down the registry drive). - New ui-goal browser-plugin spec exercises the plugin body over a real cordis Context with fake faces: dock registration (id/order), verbs reading the CAS ref from the current projected value, the no-current-goal short circuit, RPC-error mapping, HMR disposal, the GoalDock adapter's three projection states, and the inert node half.
This commit is contained in:
@@ -100,6 +100,10 @@ export function applyGoalProjection(state: GoalProjection | null, event: Session
|
||||
const source = event.data.source
|
||||
if (source.kind !== 'goal' || source.round !== 0) return state
|
||||
const change = source.change
|
||||
// Session-log data is a durable boundary: the static type promises the kind,
|
||||
// but a foreign or corrupted change record must degrade to same-reference,
|
||||
// never feed the zod parse in the registry drive.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- durable-boundary guard
|
||||
if (change === undefined || change.kind !== 'goal/change') return state
|
||||
if (change.operation === 'clear') return null
|
||||
return {
|
||||
|
||||
@@ -46,7 +46,7 @@ function liveAgent(ctx: Context, session: Session): Agent {
|
||||
},
|
||||
cancel() {},
|
||||
whenIdle() { return Promise.resolve() },
|
||||
} as Agent
|
||||
}
|
||||
ctx.agents.register(agent)
|
||||
return agent
|
||||
}
|
||||
@@ -63,7 +63,7 @@ async function harness(withGoal: boolean): Promise<Bench> {
|
||||
ctx,
|
||||
session,
|
||||
agent,
|
||||
tailValues: () => ctx.sessionProjections.snapshot(session).values as Record<string, unknown>,
|
||||
tailValues: () => ctx.sessionProjections.snapshot(session).values,
|
||||
tailAsOfSeq: () => ctx.sessionProjections.snapshot(session).asOfSeq,
|
||||
}
|
||||
}
|
||||
@@ -142,6 +142,18 @@ describe('goal projection unit', () => {
|
||||
// Same-reference return: the registry's Object.is gate sees no change.
|
||||
expect(applyGoalProjection(state, malformed)).toBe(state)
|
||||
expect(applyGoalProjection(null, malformed)).toBeNull()
|
||||
|
||||
// A non-message event (the registry drives EVERY committed event through
|
||||
// apply): early same-reference return.
|
||||
const turnStart = { type: 'turn/start', seq: 3, time: 4, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } } as never
|
||||
expect(applyGoalProjection(state, turnStart)).toBe(state)
|
||||
|
||||
// A round-zero goal source whose change carries a foreign kind: same posture.
|
||||
const foreignKind = { type: 'user/message', seq: 2, time: 3, data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'foreign' }],
|
||||
source: { kind: 'goal', goalId: 'g1', revision: 1, round: 0, change: { kind: 'not-a-goal-change' } } as never,
|
||||
}) } as never
|
||||
expect(applyGoalProjection(state, foreignKind)).toBe(state)
|
||||
})
|
||||
|
||||
it('has no goal key when the goal service is not composed', async () => {
|
||||
|
||||
Reference in New Issue
Block a user