fix(team): tighten pending launch runtime reporting
This commit is contained in:
parent
9005deb05c
commit
1cb9af3fc7
4 changed files with 117 additions and 8 deletions
|
|
@ -11888,11 +11888,10 @@ export class TeamProvisioningService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const member = snapshot.members[memberName];
|
const member = snapshot.members[memberName];
|
||||||
return (
|
if (!member) {
|
||||||
member &&
|
return true;
|
||||||
member.launchState !== 'confirmed_alive' &&
|
}
|
||||||
member.launchState !== 'failed_to_start'
|
return member.launchState !== 'confirmed_alive' && member.launchState !== 'failed_to_start';
|
||||||
);
|
|
||||||
});
|
});
|
||||||
if (secondaryPendingMembers.length === 0) {
|
if (secondaryPendingMembers.length === 0) {
|
||||||
return this.buildPendingBootstrapStatusMessage(prefix, run, launchSummary);
|
return this.buildPendingBootstrapStatusMessage(prefix, run, launchSummary);
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,11 @@ export function resolveMemberRuntimeSummary(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMemberLaunchPending(spawnEntry)) {
|
if (isMemberLaunchPending(spawnEntry)) {
|
||||||
return undefined;
|
if (!configuredModel.length && !memorySuffix) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const summary = formatTeamModelSummary(configuredProvider, configuredModel, configuredEffort);
|
||||||
|
return `${summary}${backendLabel ? ` · ${backendLabel}` : ''}${memorySuffix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const summary = formatTeamModelSummary(configuredProvider, configuredModel, configuredEffort);
|
const summary = formatTeamModelSummary(configuredProvider, configuredModel, configuredEffort);
|
||||||
|
|
|
||||||
|
|
@ -1921,6 +1921,86 @@ describe('TeamProvisioningService', () => {
|
||||||
expect(message).toBe('Finishing launch - waiting for secondary runtime lane: bob');
|
expect(message).toBe('Finishing launch - waiting for secondary runtime lane: bob');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('treats missing secondary-lane snapshot members as still pending', async () => {
|
||||||
|
const svc = new TeamProvisioningService();
|
||||||
|
const run = createMemberSpawnRun({
|
||||||
|
teamName: 'mixed-team',
|
||||||
|
expectedMembers: ['alice'],
|
||||||
|
memberSpawnStatuses: new Map([
|
||||||
|
[
|
||||||
|
'alice',
|
||||||
|
createMemberSpawnStatusEntry({
|
||||||
|
status: 'online',
|
||||||
|
launchState: 'confirmed_alive',
|
||||||
|
runtimeAlive: true,
|
||||||
|
bootstrapConfirmed: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
run.isLaunch = true;
|
||||||
|
run.mixedSecondaryLanes = [
|
||||||
|
{
|
||||||
|
laneId: 'secondary:opencode:bob',
|
||||||
|
providerId: 'opencode',
|
||||||
|
member: {
|
||||||
|
name: 'bob',
|
||||||
|
providerId: 'opencode',
|
||||||
|
model: 'minimax-m2.5-free',
|
||||||
|
effort: 'medium',
|
||||||
|
},
|
||||||
|
runId: 'opencode-run-1',
|
||||||
|
state: 'launching',
|
||||||
|
result: null,
|
||||||
|
warnings: [],
|
||||||
|
diagnostics: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const message = (svc as any).buildAggregatePendingLaunchMessage(
|
||||||
|
'Finishing launch',
|
||||||
|
run,
|
||||||
|
{
|
||||||
|
confirmedCount: 1,
|
||||||
|
pendingCount: 1,
|
||||||
|
failedCount: 0,
|
||||||
|
runtimeAlivePendingCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: 2,
|
||||||
|
teamName: 'mixed-team',
|
||||||
|
updatedAt: '2026-04-22T12:00:00.000Z',
|
||||||
|
launchPhase: 'active',
|
||||||
|
expectedMembers: ['alice', 'bob'],
|
||||||
|
bootstrapExpectedMembers: ['alice'],
|
||||||
|
members: {
|
||||||
|
alice: {
|
||||||
|
name: 'alice',
|
||||||
|
providerId: 'codex',
|
||||||
|
laneId: 'primary',
|
||||||
|
laneKind: 'primary',
|
||||||
|
laneOwnerProviderId: 'codex',
|
||||||
|
launchState: 'confirmed_alive',
|
||||||
|
agentToolAccepted: true,
|
||||||
|
runtimeAlive: true,
|
||||||
|
bootstrapConfirmed: true,
|
||||||
|
hardFailure: false,
|
||||||
|
lastEvaluatedAt: '2026-04-22T12:00:00.000Z',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
summary: {
|
||||||
|
confirmedCount: 1,
|
||||||
|
pendingCount: 1,
|
||||||
|
failedCount: 0,
|
||||||
|
runtimeAlivePendingCount: 0,
|
||||||
|
},
|
||||||
|
teamLaunchState: 'partial_pending',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(message).toBe('Finishing launch - waiting for secondary runtime lane: bob');
|
||||||
|
});
|
||||||
|
|
||||||
it('launches the OpenCode secondary lane with side-lane provider and member runtime identity', async () => {
|
it('launches the OpenCode secondary lane with side-lane provider and member runtime identity', async () => {
|
||||||
const svc = new TeamProvisioningService();
|
const svc = new TeamProvisioningService();
|
||||||
const adapterLaunch = vi.fn(async (input: Record<string, unknown>) => ({
|
const adapterLaunch = vi.fn(async (input: Record<string, unknown>) => ({
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,17 @@ describe('resolveMemberRuntimeSummary', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('keeps the loading skeleton when a pending member has no live runtime model yet', () => {
|
it('keeps the configured summary visible while a pending member waits for the live runtime model', () => {
|
||||||
const member = createMember();
|
const member = createMember({ model: 'gpt-5.4-mini' });
|
||||||
|
const spawnEntry = createSpawnEntry();
|
||||||
|
|
||||||
|
expect(resolveMemberRuntimeSummary(member, undefined, spawnEntry)).toBe(
|
||||||
|
'5.4 Mini · Medium · Codex'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('still keeps the loading skeleton when a pending member has neither live nor configured model truth', () => {
|
||||||
|
const member = createMember({ model: undefined });
|
||||||
const spawnEntry = createSpawnEntry();
|
const spawnEntry = createSpawnEntry();
|
||||||
|
|
||||||
expect(resolveMemberRuntimeSummary(member, undefined, spawnEntry)).toBeUndefined();
|
expect(resolveMemberRuntimeSummary(member, undefined, spawnEntry)).toBeUndefined();
|
||||||
|
|
@ -85,6 +94,23 @@ describe('resolveMemberRuntimeSummary', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('appends runtime memory while a configured member is still pending', () => {
|
||||||
|
const member = createMember({ model: 'gpt-5.4-mini' });
|
||||||
|
const spawnEntry = createSpawnEntry();
|
||||||
|
const runtimeEntry = {
|
||||||
|
memberName: 'alice',
|
||||||
|
alive: true,
|
||||||
|
restartable: true,
|
||||||
|
pid: 4242,
|
||||||
|
rssBytes: 256 * 1024 * 1024,
|
||||||
|
updatedAt: '2026-04-18T18:00:00.000Z',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(resolveMemberRuntimeSummary(member, undefined, spawnEntry, runtimeEntry as never)).toBe(
|
||||||
|
'5.4 Mini · Medium · Codex · 256.0 MB'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('keeps the persisted backend lane visible in the runtime summary', () => {
|
it('keeps the persisted backend lane visible in the runtime summary', () => {
|
||||||
const member = createMember({ model: 'gpt-5.4-mini' });
|
const member = createMember({ model: 'gpt-5.4-mini' });
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue