fix(pi): retain ownership for uncertain mutations

This commit is contained in:
2026-08-25 23:53:54 +08:00
parent 621ebb1781
commit 019cbb115a
21 changed files with 1113 additions and 67 deletions

View File

@@ -580,12 +580,22 @@ export async function runPackagedProductProof(options) {
const backgroundActive = await waitForResilienceProof(
electronApplication,
(status) => status?.target?.runStatus === 'running'
&& status?.target?.errorCode === 'CODING_REQUEST_UNCERTAIN'
&& status?.other?.runStatus === 'running'
&& status?.activeProviderRequests?.parent === 2
&& status?.resources?.backgroundLeases?.active === 2
&& status?.processes?.parent?.length === 2,
'Packaged background lease proof did not reach two active Main-owned runs',
);
const uncertaintyMessage = page.getByText(/请求确认延迟,可能仍在执行/).last();
await uncertaintyMessage.waitFor({ state: 'visible', timeout: 15_000 });
const compactButton = page.getByRole('button', { name: '整理上下文' });
if (await compactButton.isEnabled()) {
throw new Error('Packaged UI allowed compact to overlap a confirmation-uncertain prompt');
}
if (await page.getByText(/本地编程运行时暂时不可用/).count()) {
throw new Error('Confirmation uncertainty was presented as a local runtime outage');
}
await setMainWindowVisible(electronApplication, false);
await new Promise((resolveWait) => setTimeout(resolveWait, 600));
const backgroundHidden = await evaluateProof(electronApplication, 'resilience.status');
@@ -609,6 +619,44 @@ export async function runPackagedProductProof(options) {
if (!await resilienceComposer.isEnabled()) {
throw new Error('Packaged composer stayed disabled after the hidden run settled');
}
await uncertaintyMessage.waitFor({ state: 'hidden', timeout: 10_000 });
const compactDelay = await evaluateProof(electronApplication, 'resilience.arm-compact-delay');
assertPackagedMain(compactDelay);
if (!(compactDelay?.resilience?.delayMs > 10_000)) {
throw new Error(`Packaged compact proof did not exceed the former 10s threshold: ${JSON.stringify(compactDelay?.resilience)}`);
}
await compactButton.click();
await uncertaintyMessage.waitFor({ state: 'visible', timeout: 15_000 });
const compactUncertain = await waitForResilienceProof(
electronApplication,
(status) => status?.target?.runStatus === 'compacting'
&& status?.target?.errorCode === 'CODING_REQUEST_UNCERTAIN'
&& status?.target?.contextCompaction === 'running'
&& status?.activeProviderRequests?.parent === 1
&& status?.resources?.backgroundLeases?.active === 1,
'Packaged manual compact did not retain ownership after the 10s confirmation threshold',
);
if (await compactButton.isEnabled()) {
throw new Error('Packaged UI enabled another compact while the first compact was uncertain');
}
if (await page.getByText(/本地编程运行时暂时不可用/).count()) {
throw new Error('Packaged manual compact uncertainty was presented as a local runtime outage');
}
const compactSettled = await waitForResilienceProof(
electronApplication,
(status) => status?.target?.runStatus === 'idle'
&& status?.target?.errorCode === null
&& status?.target?.contextCompaction === 'idle'
&& status?.target?.completedCompactions >= 1
&& status?.activeProviderRequests?.parent === 0
&& status?.resources?.backgroundLeases?.active === 0,
'Packaged manual compact did not settle and release its Main-owned lease',
);
await uncertaintyMessage.waitFor({ state: 'hidden', timeout: 10_000 });
if (!await resilienceComposer.isEnabled()) {
throw new Error('Packaged composer stayed disabled after manual compact settled');
}
await setMainWindowVisible(electronApplication, false);
const backgroundIdle = await waitForResilienceIdleProof(
electronApplication,
@@ -849,10 +897,19 @@ export async function runPackagedProductProof(options) {
active: backgroundActive.resilience,
hiddenPastGrace: backgroundHidden.resilience,
idleEvicted: backgroundIdle.resilience,
uiPromptAccepted: true,
uiPromptSubmitted: true,
hostConfirmationUncertain: true,
answerVisibleAfterShow: true,
composerUnlocked: true,
},
delayedCompact: {
configured: compactDelay.resilience,
uncertain: compactUncertain.resilience,
settled: compactSettled.resilience,
overlappingMutationBlocked: true,
runtimeUnavailableBanner: false,
composerUnlocked: true,
},
intentionalDispose: {
active: intentionalActive.resilience,
disposed: intentionalDispose.resilience,