fix(team): keep launch failure copy without live details
This commit is contained in:
parent
1cb9af3fc7
commit
065ec81466
2 changed files with 124 additions and 3 deletions
|
|
@ -108,6 +108,19 @@ function buildFailedSpawnCompactDetail(
|
||||||
return `${failedSpawnDetails.length} teammates failed to start`;
|
return `${failedSpawnDetails.length} teammates failed to start`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildGenericFailedSpawnPanelMessage(
|
||||||
|
failedSpawnCount: number,
|
||||||
|
expectedTeammateCount: number
|
||||||
|
): string | null {
|
||||||
|
if (failedSpawnCount <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (failedSpawnCount === 1) {
|
||||||
|
return '1 teammate failed to start';
|
||||||
|
}
|
||||||
|
return `${failedSpawnCount}/${Math.max(expectedTeammateCount, failedSpawnCount)} teammates failed to start`;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TeamProvisioningPresentation {
|
export interface TeamProvisioningPresentation {
|
||||||
progress: TeamProvisioningProgress;
|
progress: TeamProvisioningProgress;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
|
@ -184,6 +197,10 @@ export function buildTeamProvisioningPresentation({
|
||||||
const failedSpawnDetails = getFailedSpawnDetails(memberSpawnStatuses);
|
const failedSpawnDetails = getFailedSpawnDetails(memberSpawnStatuses);
|
||||||
const failedSpawnPanelMessage = buildFailedSpawnPanelMessage(failedSpawnDetails);
|
const failedSpawnPanelMessage = buildFailedSpawnPanelMessage(failedSpawnDetails);
|
||||||
const failedSpawnCompactDetail = buildFailedSpawnCompactDetail(failedSpawnDetails);
|
const failedSpawnCompactDetail = buildFailedSpawnCompactDetail(failedSpawnDetails);
|
||||||
|
const genericFailedSpawnPanelMessage = buildGenericFailedSpawnPanelMessage(
|
||||||
|
failedSpawnCount,
|
||||||
|
expectedTeammateCount
|
||||||
|
);
|
||||||
|
|
||||||
const { allTeammatesConfirmedAlive, hasMembersStillJoining, remainingJoinCount } =
|
const { allTeammatesConfirmedAlive, hasMembersStillJoining, remainingJoinCount } =
|
||||||
getLaunchJoinState({
|
getLaunchJoinState({
|
||||||
|
|
@ -220,7 +237,7 @@ export function buildTeamProvisioningPresentation({
|
||||||
hasMembersStillJoining,
|
hasMembersStillJoining,
|
||||||
remainingJoinCount,
|
remainingJoinCount,
|
||||||
panelTitle: 'Launch failed',
|
panelTitle: 'Launch failed',
|
||||||
panelMessage: progress.error ?? failedSpawnPanelMessage ?? null,
|
panelMessage: progress.error ?? failedSpawnPanelMessage ?? genericFailedSpawnPanelMessage,
|
||||||
panelTone: 'error',
|
panelTone: 'error',
|
||||||
defaultLiveOutputOpen: true,
|
defaultLiveOutputOpen: true,
|
||||||
compactTitle: 'Launch failed',
|
compactTitle: 'Launch failed',
|
||||||
|
|
@ -245,7 +262,7 @@ export function buildTeamProvisioningPresentation({
|
||||||
: `All ${expectedTeammateCount} teammates joined`;
|
: `All ${expectedTeammateCount} teammates joined`;
|
||||||
const readyDetailMessage =
|
const readyDetailMessage =
|
||||||
failedSpawnCount > 0
|
failedSpawnCount > 0
|
||||||
? (failedSpawnPanelMessage ?? progress.message)
|
? (failedSpawnPanelMessage ?? genericFailedSpawnPanelMessage ?? progress.message)
|
||||||
: expectedTeammateCount === 0
|
: expectedTeammateCount === 0
|
||||||
? 'Team provisioned - lead online'
|
? 'Team provisioned - lead online'
|
||||||
: allTeammatesConfirmedAlive
|
: allTeammatesConfirmedAlive
|
||||||
|
|
@ -316,7 +333,9 @@ export function buildTeamProvisioningPresentation({
|
||||||
remainingJoinCount,
|
remainingJoinCount,
|
||||||
panelTitle: 'Launching team',
|
panelTitle: 'Launching team',
|
||||||
panelMessage:
|
panelMessage:
|
||||||
failedSpawnCount > 0 ? (failedSpawnPanelMessage ?? progress.message) : progress.message,
|
failedSpawnCount > 0
|
||||||
|
? (failedSpawnPanelMessage ?? genericFailedSpawnPanelMessage ?? progress.message)
|
||||||
|
: progress.message,
|
||||||
panelMessageSeverity: failedSpawnCount > 0 ? 'warning' : progress.messageSeverity,
|
panelMessageSeverity: failedSpawnCount > 0 ? 'warning' : progress.messageSeverity,
|
||||||
defaultLiveOutputOpen: false,
|
defaultLiveOutputOpen: false,
|
||||||
compactTitle: 'Launching team',
|
compactTitle: 'Launching team',
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,57 @@ describe('buildTeamProvisioningPresentation', () => {
|
||||||
expect(presentation?.compactDetail).toBe('jack failed to start');
|
expect(presentation?.compactDetail).toBe('jack failed to start');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps a generic failed teammate message when only persisted failure counts remain', () => {
|
||||||
|
const presentation = buildTeamProvisioningPresentation({
|
||||||
|
progress: {
|
||||||
|
runId: 'run-3b',
|
||||||
|
teamName: 'codex-team',
|
||||||
|
state: 'ready',
|
||||||
|
startedAt: '2026-04-13T10:00:00.000Z',
|
||||||
|
updatedAt: '2026-04-13T10:00:08.000Z',
|
||||||
|
message: 'Launch completed',
|
||||||
|
messageSeverity: undefined,
|
||||||
|
pid: 4321,
|
||||||
|
cliLogsTail: '',
|
||||||
|
assistantOutput: '',
|
||||||
|
},
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'team-lead',
|
||||||
|
agentType: 'team-lead',
|
||||||
|
status: 'active',
|
||||||
|
currentTaskId: null,
|
||||||
|
taskCount: 0,
|
||||||
|
lastActiveAt: null,
|
||||||
|
messageCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'jack',
|
||||||
|
agentType: 'engineer',
|
||||||
|
status: 'unknown',
|
||||||
|
currentTaskId: null,
|
||||||
|
taskCount: 0,
|
||||||
|
lastActiveAt: null,
|
||||||
|
messageCount: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
memberSpawnStatuses: {},
|
||||||
|
memberSpawnSnapshot: {
|
||||||
|
expectedMembers: ['jack'],
|
||||||
|
summary: {
|
||||||
|
confirmedCount: 0,
|
||||||
|
pendingCount: 0,
|
||||||
|
failedCount: 1,
|
||||||
|
runtimeAlivePendingCount: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(presentation?.successMessage).toBe('Launch finished with errors - 1/1 teammates failed to start');
|
||||||
|
expect(presentation?.panelMessage).toBe('1 teammate failed to start');
|
||||||
|
expect(presentation?.compactDetail).toBe('1 teammate failed to start');
|
||||||
|
});
|
||||||
|
|
||||||
it('prefers live member spawn statuses over a stale persisted launch summary', () => {
|
it('prefers live member spawn statuses over a stale persisted launch summary', () => {
|
||||||
const presentation = buildTeamProvisioningPresentation({
|
const presentation = buildTeamProvisioningPresentation({
|
||||||
progress: {
|
progress: {
|
||||||
|
|
@ -218,6 +269,57 @@ describe('buildTeamProvisioningPresentation', () => {
|
||||||
expect(presentation?.panelMessage).toBe('1 teammate still joining');
|
expect(presentation?.panelMessage).toBe('1 teammate still joining');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps a generic failed teammate message while launch is still active if only persisted failure counts remain', () => {
|
||||||
|
const presentation = buildTeamProvisioningPresentation({
|
||||||
|
progress: {
|
||||||
|
runId: 'run-4b',
|
||||||
|
teamName: 'codex-team',
|
||||||
|
state: 'assembling',
|
||||||
|
startedAt: '2026-04-13T10:00:00.000Z',
|
||||||
|
updatedAt: '2026-04-13T10:00:05.000Z',
|
||||||
|
message: 'Finalizing launch...',
|
||||||
|
messageSeverity: undefined,
|
||||||
|
pid: 4321,
|
||||||
|
cliLogsTail: '',
|
||||||
|
assistantOutput: '',
|
||||||
|
},
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'team-lead',
|
||||||
|
agentType: 'team-lead',
|
||||||
|
status: 'active',
|
||||||
|
currentTaskId: null,
|
||||||
|
taskCount: 0,
|
||||||
|
lastActiveAt: null,
|
||||||
|
messageCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'jack',
|
||||||
|
agentType: 'engineer',
|
||||||
|
status: 'unknown',
|
||||||
|
currentTaskId: null,
|
||||||
|
taskCount: 0,
|
||||||
|
lastActiveAt: null,
|
||||||
|
messageCount: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
memberSpawnStatuses: {},
|
||||||
|
memberSpawnSnapshot: {
|
||||||
|
expectedMembers: ['jack'],
|
||||||
|
summary: {
|
||||||
|
confirmedCount: 0,
|
||||||
|
pendingCount: 0,
|
||||||
|
failedCount: 1,
|
||||||
|
runtimeAlivePendingCount: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(presentation?.panelMessage).toBe('1 teammate failed to start');
|
||||||
|
expect(presentation?.compactDetail).toBe('1 teammate failed to start');
|
||||||
|
expect(presentation?.compactTone).toBe('warning');
|
||||||
|
});
|
||||||
|
|
||||||
it('prefers live confirmed teammates over a stale persisted launch summary', () => {
|
it('prefers live confirmed teammates over a stale persisted launch summary', () => {
|
||||||
const presentation = buildTeamProvisioningPresentation({
|
const presentation = buildTeamProvisioningPresentation({
|
||||||
progress: {
|
progress: {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue