fix(team): tighten pending launch runtime reporting

This commit is contained in:
777genius 2026-04-23 00:36:22 +03:00
parent 9005deb05c
commit 1cb9af3fc7
4 changed files with 117 additions and 8 deletions

View file

@ -11888,11 +11888,10 @@ export class TeamProvisioningService {
return false;
}
const member = snapshot.members[memberName];
return (
member &&
member.launchState !== 'confirmed_alive' &&
member.launchState !== 'failed_to_start'
);
if (!member) {
return true;
}
return member.launchState !== 'confirmed_alive' && member.launchState !== 'failed_to_start';
});
if (secondaryPendingMembers.length === 0) {
return this.buildPendingBootstrapStatusMessage(prefix, run, launchSummary);

View file

@ -77,7 +77,11 @@ export function resolveMemberRuntimeSummary(
}
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);

View file

@ -1921,6 +1921,86 @@ describe('TeamProvisioningService', () => {
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 () => {
const svc = new TeamProvisioningService();
const adapterLaunch = vi.fn(async (input: Record<string, unknown>) => ({

View file

@ -47,8 +47,17 @@ describe('resolveMemberRuntimeSummary', () => {
);
});
it('keeps the loading skeleton when a pending member has no live runtime model yet', () => {
const member = createMember();
it('keeps the configured summary visible while a pending member waits for the live runtime model', () => {
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();
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', () => {
const member = createMember({ model: 'gpt-5.4-mini' });