fix(team): reconcile richer persisted launch members
This commit is contained in:
parent
be76b332c9
commit
1223fa236a
2 changed files with 67 additions and 2 deletions
|
|
@ -12639,8 +12639,9 @@ export class TeamProvisioningService {
|
||||||
|
|
||||||
const liveAgentNames = await this.getLiveTeamAgentNames(teamName);
|
const liveAgentNames = await this.getLiveTeamAgentNames(teamName);
|
||||||
const nextMembers = { ...persisted.members };
|
const nextMembers = { ...persisted.members };
|
||||||
|
const persistedMemberNames = this.getPersistedLaunchMemberNames(persisted);
|
||||||
const now = nowIso();
|
const now = nowIso();
|
||||||
for (const expected of persisted.expectedMembers) {
|
for (const expected of persistedMemberNames) {
|
||||||
const bootstrapMember = bootstrapSnapshot?.members[expected];
|
const bootstrapMember = bootstrapSnapshot?.members[expected];
|
||||||
const current = nextMembers[expected] ?? {
|
const current = nextMembers[expected] ?? {
|
||||||
name: expected,
|
name: expected,
|
||||||
|
|
@ -12772,7 +12773,7 @@ export class TeamProvisioningService {
|
||||||
|
|
||||||
const reconciled = createPersistedLaunchSnapshot({
|
const reconciled = createPersistedLaunchSnapshot({
|
||||||
teamName,
|
teamName,
|
||||||
expectedMembers: persisted.expectedMembers,
|
expectedMembers: persistedMemberNames,
|
||||||
leadSessionId: persisted.leadSessionId,
|
leadSessionId: persisted.leadSessionId,
|
||||||
launchPhase: persisted.launchPhase === 'active' ? 'active' : 'reconciled',
|
launchPhase: persisted.launchPhase === 'active' ? 'active' : 'reconciled',
|
||||||
members: nextMembers,
|
members: nextMembers,
|
||||||
|
|
|
||||||
|
|
@ -5738,6 +5738,70 @@ describe('TeamProvisioningService', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('reconciles extra persisted launch members when bootstrap state proves they were registered', async () => {
|
||||||
|
const teamName = 'registered-bootstrap-extra-member-team';
|
||||||
|
const teamDir = path.join(tempTeamsBase, teamName);
|
||||||
|
fs.mkdirSync(teamDir, { recursive: true });
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(teamDir, 'launch-state.json'),
|
||||||
|
JSON.stringify(
|
||||||
|
createPersistedLaunchSnapshot({
|
||||||
|
teamName,
|
||||||
|
leadSessionId: 'lead-session',
|
||||||
|
launchPhase: 'active',
|
||||||
|
expectedMembers: ['alice'],
|
||||||
|
members: {
|
||||||
|
alice: {
|
||||||
|
name: 'alice',
|
||||||
|
launchState: 'confirmed_alive',
|
||||||
|
agentToolAccepted: true,
|
||||||
|
runtimeAlive: true,
|
||||||
|
bootstrapConfirmed: true,
|
||||||
|
hardFailure: false,
|
||||||
|
lastEvaluatedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
bob: {
|
||||||
|
name: 'bob',
|
||||||
|
launchState: 'failed_to_start',
|
||||||
|
agentToolAccepted: false,
|
||||||
|
runtimeAlive: false,
|
||||||
|
bootstrapConfirmed: false,
|
||||||
|
hardFailure: true,
|
||||||
|
hardFailureReason: 'Teammate was never spawned during launch.',
|
||||||
|
lastEvaluatedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
writeBootstrapState(
|
||||||
|
teamName,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'bob',
|
||||||
|
status: 'registered',
|
||||||
|
lastAttemptAt: Date.now() - 60_000,
|
||||||
|
lastObservedAt: Date.now() - 60_000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
new Date(Date.now() - 30_000).toISOString()
|
||||||
|
);
|
||||||
|
|
||||||
|
const svc = new TeamProvisioningService();
|
||||||
|
const result = await svc.getMemberSpawnStatuses(teamName);
|
||||||
|
|
||||||
|
expect(result.expectedMembers).toEqual(['alice', 'bob']);
|
||||||
|
expect(result.statuses.bob).toMatchObject({
|
||||||
|
status: 'waiting',
|
||||||
|
launchState: 'runtime_pending_bootstrap',
|
||||||
|
hardFailure: false,
|
||||||
|
hardFailureReason: undefined,
|
||||||
|
agentToolAccepted: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('returns persisted expectedMembers as the union of expected and materialized launch members', async () => {
|
it('returns persisted expectedMembers as the union of expected and materialized launch members', async () => {
|
||||||
const teamName = 'persisted-union-member-spawn-team';
|
const teamName = 'persisted-union-member-spawn-team';
|
||||||
const teamDir = path.join(tempTeamsBase, teamName);
|
const teamDir = path.join(tempTeamsBase, teamName);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue