mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-01 15:30:52 +08:00
Fix Windows Plugin Gate B lifecycle timing
This commit is contained in:
@@ -166,3 +166,14 @@
|
||||
- `npm run verify:gui-smoke`:通过;最新 Electron evidence `standalone-shell-01-20260810112853-16763`,App Server `1.125.0`。
|
||||
- 本机 packaged Plugin Gate B 既有证据保持通过:`ok=true`、provider request `2`、MCP elicitation accepted、provider final text、cold restore/卸载历史和 `productionMockFallbackHitCount=0`。
|
||||
- 当前阻塞只剩危险 Git 写操作确认,以及新完整 SHA 推送后的 Windows runner Plugin Gate B/artifact 复核;既有 `v1.125.0` tag 固定在 `8647d18fa358e3a9c86e520348d39e4b3eba6041`。
|
||||
|
||||
## Windows runner `31384560366`
|
||||
|
||||
状态:`fix-validated-locally / windows-runner-pending`
|
||||
|
||||
- 使用完整 SHA `668699a4d29a4302e7db46aaab58644f2e46b61a`;Windows Plugin path contract、sherpa runtime、Electron Windows x64 Squirrel package、N-1 installer 下载与 installed Squirrel smoke 全部通过。
|
||||
- Plugin Gate B 已通过 App Center 安装/启停、禁用边界、provider 两次请求、MCP elicitation、最终文本与 canonical MCP App item 投影;唯一失败是首次显式恢复后等待固定累计 `2` 次 resource read/HTML load。
|
||||
- 失败 evidence 同时证明 WebContents marker 已加载且 MCP ledger 已有 `1` 次 `resource_read`。脚本在 reload 前没有等待隐式首次挂载,Windows 上 reload 抢先后只有一次有效加载;随后 60 秒等待使 240 条 invoke trace ring buffer 被 drain 记录覆盖,最终诊断误显示计数为 `0`。
|
||||
- 修复:首次显式恢复只要求至少一组 resource read/HTML load 且一一对应;下一次 Renderer reload 按已观察基线要求各精确增加一次;cold restore 继续要求独立进程增加一次。最终有效最小计数从依赖隐式竞态的 `4` 收敛为确定性的 `3`,不放宽任何真实产品边界。
|
||||
- 本地验证:Gate B 脚本 Vitest `8 passed; 0 failed`、定向 ESLint、Node 语法检查、`npm run typecheck`、`npm run test:contracts`、`npm run verify:app-version` 全部通过。本机真实 Electron Plugin Gate B `ok=true`,resource read/HTML load `4/4`、launch `2`、provider request `2`、reload/cold restore/卸载历史全部通过、`productionMockFallbackHitCount=0`、`missingRequiredMethods=[]`。
|
||||
- 下一步:通过 Gate B 脚本单测、定向 ESLint、contracts 与本机 packaged Gate B 后,提交/推送窄修复并以新完整 SHA 重跑 Windows runner;`v1.125.0` tag 不移动。
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
installPluginPackageEmbeddedBrowserLifecycleCapture,
|
||||
PLUGIN_PACKAGE_MCP_APP_MARKER,
|
||||
PLUGIN_PACKAGE_MCP_APP_RESOURCE_URI,
|
||||
pluginPackageMcpAppLifecycleDelta,
|
||||
pluginPackageMcpAppHtml,
|
||||
waitForPluginPackageMcpAppHistoryUnavailable,
|
||||
waitForPluginPackageMcpAppSurface,
|
||||
@@ -2452,14 +2453,15 @@ export async function run({ pluginPackage = false } = {}) {
|
||||
page,
|
||||
options,
|
||||
runtime,
|
||||
minimumResourceReadCount: 2,
|
||||
minimumHtmlLoadCount: 2,
|
||||
minimumResourceReadCount: 1,
|
||||
minimumHtmlLoadCount: 1,
|
||||
});
|
||||
raw.mcpAppFirstSurface = sanitizeJson(firstSurface);
|
||||
assert(
|
||||
firstSurface.traceEvidence.resourceReadCount === 2 &&
|
||||
firstSurface.traceEvidence.htmlLoadCount === 2,
|
||||
`首次显式恢复前后的 MCP App resource/HTML load 计数异常: ${JSON.stringify(
|
||||
firstSurface.traceEvidence.resourceReadCount >= 1 &&
|
||||
firstSurface.traceEvidence.resourceReadCount ===
|
||||
firstSurface.traceEvidence.htmlLoadCount,
|
||||
`首次显式恢复的 MCP App resource/HTML load 计数异常: ${JSON.stringify(
|
||||
firstSurface.traceEvidence,
|
||||
)}`,
|
||||
);
|
||||
@@ -2488,13 +2490,18 @@ export async function run({ pluginPackage = false } = {}) {
|
||||
page,
|
||||
options,
|
||||
runtime,
|
||||
minimumResourceReadCount: 3,
|
||||
minimumHtmlLoadCount: 3,
|
||||
minimumResourceReadCount:
|
||||
firstSurface.traceEvidence.resourceReadCount + 1,
|
||||
minimumHtmlLoadCount: firstSurface.traceEvidence.htmlLoadCount + 1,
|
||||
});
|
||||
const restoredLifecycleDelta = pluginPackageMcpAppLifecycleDelta(
|
||||
firstSurface.traceEvidence,
|
||||
restoredSurface.traceEvidence,
|
||||
);
|
||||
assert(
|
||||
restoredSurface.traceEvidence.resourceReadCount === 3 &&
|
||||
restoredSurface.traceEvidence.htmlLoadCount === 3,
|
||||
"Renderer reload 后 MCP App resource/HTML load 计数异常",
|
||||
restoredLifecycleDelta.resourceReadCount === 1 &&
|
||||
restoredLifecycleDelta.htmlLoadCount === 1,
|
||||
`Renderer reload 后 MCP App resource/HTML load 增量异常: ${JSON.stringify(restoredLifecycleDelta)}`,
|
||||
);
|
||||
summary.mcpAppRestoredAfterReload = true;
|
||||
summary.mcpAppCanonicalIdentityStable =
|
||||
@@ -2502,6 +2509,9 @@ export async function run({ pluginPackage = false } = {}) {
|
||||
restoredSurface.viewId === firstSurface.viewId;
|
||||
raw.mcpAppRestoredRead = sanitizeJson(restoredRead);
|
||||
raw.mcpAppRestoredSurface = sanitizeJson(restoredSurface);
|
||||
raw.mcpAppRestoredLifecycleDelta = sanitizeJson(
|
||||
restoredLifecycleDelta,
|
||||
);
|
||||
await page.screenshot({ path: screenshotPath, fullPage: true });
|
||||
|
||||
const preColdRestoreLedger = readJsonLines(mcpFixture.ledgerPath);
|
||||
@@ -2895,7 +2905,7 @@ export async function run({ pluginPackage = false } = {}) {
|
||||
"Plugin MCP App canonical identity 不稳定",
|
||||
);
|
||||
assert(
|
||||
summary.mcpAppResourceReadCount >= 4,
|
||||
summary.mcpAppResourceReadCount >= 3,
|
||||
`Plugin MCP App resource read 次数异常: ${summary.mcpAppResourceReadCount}`,
|
||||
);
|
||||
assert(
|
||||
|
||||
@@ -120,6 +120,17 @@ export function pluginPackageMcpAppSurfaceReady(
|
||||
);
|
||||
}
|
||||
|
||||
export function pluginPackageMcpAppLifecycleDelta(previous, current) {
|
||||
return {
|
||||
htmlLoadCount:
|
||||
readLifecycleCount(current?.htmlLoadCount) -
|
||||
readLifecycleCount(previous?.htmlLoadCount),
|
||||
resourceReadCount:
|
||||
readLifecycleCount(current?.resourceReadCount) -
|
||||
readLifecycleCount(previous?.resourceReadCount),
|
||||
};
|
||||
}
|
||||
|
||||
export async function installPluginPackageEmbeddedBrowserLifecycleCapture(page) {
|
||||
await page.evaluate(() => {
|
||||
const stateKey = "__LIME_PLUGIN_PACKAGE_EMBEDDED_BROWSER_LIFECYCLE__";
|
||||
@@ -489,3 +500,7 @@ function parseJsonRpcLine(lines) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function readLifecycleCount(value) {
|
||||
return Number.isInteger(value) && value >= 0 ? value : 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import fs from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { pluginPackageMcpAppSurfaceReady } from "./plugin-mcp-app-gate-b.mjs";
|
||||
import {
|
||||
pluginPackageMcpAppLifecycleDelta,
|
||||
pluginPackageMcpAppSurfaceReady,
|
||||
} from "./plugin-mcp-app-gate-b.mjs";
|
||||
|
||||
describe("Plugin package current Electron fixture guard", () => {
|
||||
it("uses the real Plugin package install and runtime MCP lifecycle", () => {
|
||||
@@ -106,7 +109,7 @@ describe("Plugin package current Electron fixture guard", () => {
|
||||
expect(gate).toContain("summary.coldRestoreMcpProcessRestarted");
|
||||
expect(gate).toContain("summary.coldRestoreProviderNotReexecuted");
|
||||
expect(gate).toContain("summary.coldRestoreToolNotReexecuted");
|
||||
expect(gate).toContain("summary.mcpAppResourceReadCount >= 4");
|
||||
expect(gate).toContain("summary.mcpAppResourceReadCount >= 3");
|
||||
expect(gate).toContain(
|
||||
"summary.mcpAppHtmlLoadCount === summary.mcpAppResourceReadCount",
|
||||
);
|
||||
@@ -172,4 +175,19 @@ describe("Plugin package current Electron fixture guard", () => {
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("measures reload proof relative to the observed first surface", () => {
|
||||
expect(
|
||||
pluginPackageMcpAppLifecycleDelta(
|
||||
{ resourceReadCount: 1, htmlLoadCount: 1 },
|
||||
{ resourceReadCount: 2, htmlLoadCount: 2 },
|
||||
),
|
||||
).toEqual({ resourceReadCount: 1, htmlLoadCount: 1 });
|
||||
expect(
|
||||
pluginPackageMcpAppLifecycleDelta(
|
||||
{ resourceReadCount: 2, htmlLoadCount: 2 },
|
||||
{ resourceReadCount: 3, htmlLoadCount: 3 },
|
||||
),
|
||||
).toEqual({ resourceReadCount: 1, htmlLoadCount: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user