test: add decision center delivery gate

This commit is contained in:
Codex
2026-05-19 10:39:06 +00:00
parent 8cdcda8b93
commit 11d7b217d9
2 changed files with 222 additions and 6 deletions
+1 -1
View File
@@ -117,7 +117,7 @@
## T23B D601 Decision Center User Service
阅读 `AGENTS.md``docs/reference/microservices.md`,运行 `bun scripts/cli.ts microservice list`,确认 `decision-center` 显示为 `providerId=D601``public=false``frontendOnly=true`、仓库 URL `https://github.com/pikasTech/unidesk`、k3s/k8s `k3s://unidesk/decision-center:4277` 逻辑服务映射、`deployment.mode=k3sctl-managed``runtime.orchestrator=k3sctl` 且无业务直连容器摘要;运行 `bun scripts/cli.ts deploy apply --service decision-center --run-now`,确认命令在运行时变更前返回结构化错误,说明维护通道直连 D601 不承担服务部署;Decision Center 后续版本部署必须经未来受控 target-side CD 路径。随后运行 `bun scripts/cli.ts microservice health decision-center`,确认 `service=decision-center``storage=postgres``schemaReady=true` 且 health 中包含 `diaryEntryCount`;准备一份临时 Markdown 会议记录,运行 `bun scripts/cli.ts decision upload <markdown-file> --title <title> --type meeting --level G1 --status active --evidence <url>`,再运行 `bun scripts/cli.ts decision list``bun scripts/cli.ts decision show <id>`,确认 CLI 只通过 backend-core 用户服务代理访问,返回结构化 JSON 且能看到刚上传的记录。再准备一份包含 `# 2026年5月1日``# 2026年5月2日` 的临时工作日志 Markdown,运行 `bun scripts/cli.ts decision diary import <markdown-file> --source-file test-work-log.md --tag e2e``bun scripts/cli.ts decision diary months``bun scripts/cli.ts decision diary list --month 2026-05``bun scripts/cli.ts decision diary show 2026-05-01`,确认日记按 `YYYY-MM/YYYY-MM-DD.md` 虚拟路径拆分、写入 PostgreSQL重复导入幂等。最后登录公网 frontend `http://74.48.78.17:18081/`,进入 `用户服务 / Decision Center`,确认页面显示 G0/G1 目标、P0/P1 Blocker、停放事项、最近会议/决议、筛选、全部记录表和工作日记标签;日记标签可按月筛选并查看单日 Markdown 正文;页面不得提供聊天/LLM 会话窗口,默认不得裸 JSON,完整 JSON 只能通过 `查看原始JSON` 打开。
阅读 `AGENTS.md``docs/reference/microservices.md`,运行 `bun scripts/cli.ts microservice list`,确认 `decision-center` 显示为 `providerId=D601``public=false``frontendOnly=true`、仓库 URL `https://github.com/pikasTech/unidesk`、k3s/k8s `k3s://unidesk/decision-center:4277` 逻辑服务映射、`deployment.mode=k3sctl-managed``runtime.orchestrator=k3sctl` 且无业务直连容器摘要。随后运行 `bun scripts/cli.ts microservice health decision-center`,确认 `service=decision-center``storage=postgres``schemaReady=true` 且 health 中包含 `diaryEntryCount`;准备一份临时 Markdown 会议记录,运行 `bun scripts/cli.ts decision upload <markdown-file> --title <title> --type meeting --level G1 --status active --evidence <url>`,再运行 `bun scripts/cli.ts decision list``bun scripts/cli.ts decision show <id>`,确认 CLI 只通过 backend-core 用户服务代理访问,返回结构化 JSON 且能看到刚上传的记录。再准备一份包含 `# 2026年5月1日``# 2026年5月2日` 的临时工作日志 Markdown,运行 `bun scripts/cli.ts decision diary import <markdown-file> --source-file test-work-log.md --tag e2e``bun scripts/cli.ts decision diary months``bun scripts/cli.ts decision diary list --month 2026-05``bun scripts/cli.ts decision diary show 2026-05-01``bun scripts/cli.ts decision diary upsert 2026-05-03 --body-file <markdown-file>``bun scripts/cli.ts decision diary edit 2026-05-03 --body-file <markdown-file> --tag e2e`,确认日记按 `YYYY-MM/YYYY-MM-DD.md` 虚拟路径拆分、写入 PostgreSQL重复导入幂等且历史日记可按日期编辑。用户服务上线前的 dev 自动门禁使用 focused 集合:`bun scripts/cli.ts e2e run --only microservice:decision-center-record-crud,microservice:decision-center-diary-lifecycle,frontend:decision-center-visible,frontend:decision-center-demand-management-visible,frontend:decision-center-diary-visible`,该门禁只验证用户服务行为,不测试 CI/CD 自举,也不部署 prod。最后登录公网 frontend `http://74.48.78.17:18081/`,进入 `用户服务 / Decision Center`,确认页面显示 G0/G1 目标、P0/P1 Blocker、停放事项、最近会议/决议、需求管理工作区、需求录入编辑器、全部记录表和工作日记编辑台;日记页支持“今天”自动填入真实日期、保存当天 Markdown、编辑历史 Markdown 并再次读取一致。prod 人工验收必须在 CD 拉取已发布 artifact 后执行,逐项确认 health、records、diary editor、frontend 页面、无公网业务端口、live commit / artifact 信息;页面不得提供聊天/LLM 会话窗口,默认不得裸 JSON,完整 JSON 只能通过 `查看原始JSON` 打开。
## T24 MET Nonlinear D601 GPU User Service
+221 -5
View File
@@ -103,6 +103,8 @@ const SERVICE_CHECK_NAMES = [
"microservice:decision-center-status",
"microservice:decision-center-health",
"microservice:decision-center-records",
"microservice:decision-center-record-crud",
"microservice:decision-center-diary-lifecycle",
"microservice:oa-event-flow-status",
"microservice:oa-event-flow-health",
"microservice:oa-event-flow-diagnostics",
@@ -142,6 +144,8 @@ const FRONTEND_CHECK_NAMES = [
"frontend:findjob-integrated-visible",
"frontend:oa-event-flow-visible",
"frontend:decision-center-visible",
"frontend:decision-center-demand-management-visible",
"frontend:decision-center-diary-visible",
"frontend:code-queue-integrated-visible",
"frontend:code-queue-workdirs-loaded",
"frontend:code-queue-enqueue-await-smoke",
@@ -1385,6 +1389,66 @@ async function serviceChecks(config: UniDeskConfig, urls: PublicUrls, checks: E2
const decisionCenterStatus = apiClient.getJson("/api/microservices/decision-center/status");
const decisionCenterHealth = apiClient.getJson("/api/microservices/decision-center/health");
const decisionCenterRecords = apiClient.getJson("/api/microservices/decision-center/proxy/api/records?limit=20");
const decisionCenterRecordMarker = `E2E Decision CRUD ${Date.now()}`;
const decisionCenterRecordCreate = wantsCheck(options, "microservice:decision-center-record-crud")
? apiClient.getJson("/api/microservices/decision-center/proxy/api/records", {
method: "POST",
body: {
type: "goal",
level: "G0",
status: "active",
title: decisionCenterRecordMarker,
body: "E2E creates, edits and deletes a Decision Center requirement record.",
tags: ["e2e", "external-goal"],
evidenceLinks: ["https://example.com/unidesk/decision-center-record-crud"],
},
})
: null;
const decisionCenterRecordId = String((decisionCenterRecordCreate as { body?: { record?: { id?: string } } } | null)?.body?.record?.id || "");
const decisionCenterRecordUpdate = decisionCenterRecordId
? apiClient.getJson(`/api/microservices/decision-center/proxy/api/records/${encodeURIComponent(decisionCenterRecordId)}`, {
method: "PUT",
body: {
status: "blocked",
level: "P1",
body: "E2E edited this Decision Center requirement record before deletion.",
tags: ["e2e", "blocked"],
},
})
: { ok: false, error: "missing Decision Center record id", create: decisionCenterRecordCreate };
const decisionCenterRecordRead = decisionCenterRecordId
? apiClient.getJson(`/api/microservices/decision-center/proxy/api/records/${encodeURIComponent(decisionCenterRecordId)}`)
: { ok: false, error: "missing Decision Center record id", create: decisionCenterRecordCreate };
const decisionCenterRecordDelete = decisionCenterRecordId
? apiClient.getJson(`/api/microservices/decision-center/proxy/api/records/${encodeURIComponent(decisionCenterRecordId)}`, { method: "DELETE" })
: { ok: false, error: "missing Decision Center record id", create: decisionCenterRecordCreate };
const decisionCenterDiaryDate = "2099-12-31";
const decisionCenterDiaryMarker = `Decision Center diary lifecycle ${Date.now()}`;
const decisionCenterDiaryCreate = wantsCheck(options, "microservice:decision-center-diary-lifecycle")
? apiClient.getJson(`/api/microservices/decision-center/proxy/api/diary/entries/${decisionCenterDiaryDate}`, {
method: "PUT",
body: {
title: "E2E Decision Center Diary",
body: `# ${decisionCenterDiaryDate}\n${decisionCenterDiaryMarker}\n`,
sourceFile: "e2e-decision-center.md",
tags: ["e2e", "diary"],
},
})
: null;
const decisionCenterDiaryEdit = decisionCenterDiaryCreate
? apiClient.getJson(`/api/microservices/decision-center/proxy/api/diary/entries/${decisionCenterDiaryDate}`, {
method: "PUT",
body: {
title: "E2E Decision Center Diary Edited",
body: `# ${decisionCenterDiaryDate}\n${decisionCenterDiaryMarker}\nEdited.\n`,
sourceFile: "e2e-decision-center.md",
tags: ["e2e", "diary", "edited"],
},
})
: null;
const decisionCenterDiaryRead = decisionCenterDiaryCreate
? apiClient.getJson(`/api/microservices/decision-center/proxy/api/diary/entries/${decisionCenterDiaryDate}`)
: null;
const filebrowserHealth = apiClient.getJson("/api/microservices/filebrowser/health");
const filebrowserWebui = apiClient.getJson("/api/microservices/filebrowser/proxy/");
const filebrowserD601Health = apiClient.getJson("/api/microservices/filebrowser-d601/health");
@@ -1676,6 +1740,38 @@ async function serviceChecks(config: UniDeskConfig, urls: PublicUrls, checks: E2
addSelectedCheck(checks, options, "microservice:decision-center-status", (decisionCenterStatus as { ok?: boolean }).ok === true && (decisionCenterStatus as { body?: { microservice?: { id?: string; providerId?: string } } }).body?.microservice?.providerId === "D601", decisionCenterStatus);
addSelectedCheck(checks, options, "microservice:decision-center-health", (decisionCenterHealth as { ok?: boolean }).ok === true && decisionCenterHealthBody?.ok === true && decisionCenterHealthBody.service === "decision-center" && decisionCenterHealthBody.storage === "postgres" && decisionCenterHealthBody.schemaReady === true, decisionCenterHealth);
addSelectedCheck(checks, options, "microservice:decision-center-records", (decisionCenterRecords as { ok?: boolean }).ok === true && decisionCenterRecordsBody?.ok === true && Array.isArray(decisionCenterRecordsBody.records), decisionCenterRecords);
addSelectedCheck(checks, options, "microservice:decision-center-record-crud",
(decisionCenterRecordCreate as { ok?: boolean } | null)?.ok === true
&& (decisionCenterRecordUpdate as { ok?: boolean }).ok === true
&& (decisionCenterRecordRead as { ok?: boolean; body?: { record?: { id?: string; status?: string; level?: string; body?: string } } }).ok === true
&& (decisionCenterRecordRead as { body?: { record?: { id?: string; status?: string; level?: string; body?: string } } }).body?.record?.id === decisionCenterRecordId
&& (decisionCenterRecordRead as { body?: { record?: { status?: string; level?: string; body?: string } } }).body?.record?.status === "blocked"
&& (decisionCenterRecordRead as { body?: { record?: { status?: string; level?: string; body?: string } } }).body?.record?.level === "P1"
&& String((decisionCenterRecordRead as { body?: { record?: { body?: string } } }).body?.record?.body || "").includes("E2E edited")
&& (decisionCenterRecordDelete as { ok?: boolean }).ok === true,
{
marker: decisionCenterRecordMarker,
recordId: decisionCenterRecordId,
create: decisionCenterRecordCreate,
update: decisionCenterRecordUpdate,
read: decisionCenterRecordRead,
delete: decisionCenterRecordDelete,
});
addSelectedCheck(checks, options, "microservice:decision-center-diary-lifecycle",
(decisionCenterDiaryCreate as { ok?: boolean } | null)?.ok === true
&& (decisionCenterDiaryEdit as { ok?: boolean } | null)?.ok === true
&& (decisionCenterDiaryRead as { ok?: boolean; body?: { entry?: { date?: string; title?: string; body?: string; sourceFile?: string; tags?: string[] } } } | null)?.ok === true
&& (decisionCenterDiaryRead as { body?: { entry?: { date?: string; title?: string; body?: string; sourceFile?: string; tags?: string[] } } } | null)?.body?.entry?.date === decisionCenterDiaryDate
&& String((decisionCenterDiaryRead as { body?: { entry?: { title?: string; body?: string } } } | null)?.body?.entry?.title || "").includes("Edited")
&& String((decisionCenterDiaryRead as { body?: { entry?: { title?: string; body?: string } } } | null)?.body?.entry?.body || "").includes(decisionCenterDiaryMarker)
&& String((decisionCenterDiaryRead as { body?: { entry?: { title?: string; body?: string } } } | null)?.body?.entry?.body || "").includes("Edited."),
{
date: decisionCenterDiaryDate,
marker: decisionCenterDiaryMarker,
create: decisionCenterDiaryCreate,
edit: decisionCenterDiaryEdit,
read: decisionCenterDiaryRead,
});
const upgradeDispatch = dockerCoreJson("/api/dispatch", {
method: "POST",
body: { providerId: config.providerGateway.id, command: "provider.upgrade", payload: { source: "cli-e2e", mode: "plan" } },
@@ -1775,7 +1871,11 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
const needTodoNote = wants("frontend:todo-note-integrated-visible");
const needFindJob = wants("frontend:findjob-integrated-visible");
const needOaEventFlow = wants("frontend:oa-event-flow-visible");
const needDecisionCenter = wants("frontend:decision-center-visible");
const needDecisionCenter = wantsAny([
"frontend:decision-center-visible",
"frontend:decision-center-demand-management-visible",
"frontend:decision-center-diary-visible",
]);
const needCodeQueue = wantsAny([
"frontend:code-queue-integrated-visible",
"frontend:code-queue-workdirs-loaded",
@@ -1880,6 +1980,10 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
let decisionCenterE2eRecord: any = null;
let decisionCenterDeleteResult: any = null;
let decisionCenterMetrics: any = { pageVisible: false, tableVisible: false, rawButtonCount: 0, rawJsonBlocks: 0, chatInputCount: 0, bodyContainsRecord: false };
let decisionCenterDemandText = "";
let decisionCenterDemandMetrics: any = { workspaceVisible: false, editorVisible: false, lanes: {}, filterButtons: 0 };
let decisionCenterDiaryText = "";
let decisionCenterDiaryMetrics: any = { editorVisible: false, todayButtonVisible: false, dateValue: "", bodyValue: "", entryCards: 0, selectedHasMarker: false, duplicateDateCards: 0 };
let codeQueueText = "";
let codeQueueOutputText = "";
let codeQueueTaskCount = 0;
@@ -2187,8 +2291,12 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
});
}
if (needDecisionCenter) {
const decisionCenterE2eTitle = `E2E Decision Center ${Date.now()}`;
decisionCenterE2eRecord = await page.evaluate(async (title) => {
const decisionCenterMarker = Date.now();
const decisionCenterE2eTitle = `E2E Decision Center ${decisionCenterMarker}`;
const decisionCenterExternalGoalTitle = `E2E External Goal ${decisionCenterMarker}`;
const decisionCenterDiaryDate = "2099-12-30";
const decisionCenterDiaryMarker = `E2E diary marker ${decisionCenterMarker}`;
decisionCenterE2eRecord = await page.evaluate(async ({ title, externalGoalTitle }) => {
const response = await fetch("/api/microservices/decision-center/proxy/api/records", {
method: "POST",
credentials: "same-origin",
@@ -2203,8 +2311,30 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
evidenceLinks: ["https://example.com/unidesk/decision-center-e2e"],
}),
});
return { ok: response.ok, status: response.status, body: await response.json().catch(() => null) };
}, decisionCenterE2eTitle);
const meeting = await response.json().catch(() => null);
const goalResponse = await fetch("/api/microservices/decision-center/proxy/api/records", {
method: "POST",
credentials: "same-origin",
headers: { "content-type": "application/json" },
body: JSON.stringify({
type: "goal",
level: "G0",
status: "active",
title: externalGoalTitle,
body: "E2E seeded external goal for demand-management visibility.",
tags: ["e2e", "external-goal"],
}),
});
const goal = await goalResponse.json().catch(() => null);
return {
ok: response.ok && goalResponse.ok,
status: response.status,
body: meeting,
goalStatus: goalResponse.status,
goal,
};
}, { title: decisionCenterE2eTitle, externalGoalTitle: decisionCenterExternalGoalTitle });
const decisionCenterE2eGoalId = String(decisionCenterE2eRecord?.goal?.record?.id || "");
await page.getByRole("button", { name: /Decision Center/ }).click();
await page.waitForSelector('[data-testid="decision-center-page"]', { timeout: 10000 });
await page.waitForSelector('[data-testid="decision-center-filters"]', { timeout: 30000 });
@@ -2219,6 +2349,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
&& text.includes("查看原始JSON")
&& text.includes(String(title));
}, decisionCenterE2eTitle, { timeout: 30000 });
await page.waitForSelector('[data-testid="requirement-workspace"]', { timeout: 10000 });
decisionCenterText = await page.locator('[data-testid="decision-center-page"]').innerText({ timeout: 5000 });
decisionCenterMetrics = await page.evaluate(() => {
const root = document.querySelector('[data-testid="decision-center-page"]') as HTMLElement | null;
@@ -2234,6 +2365,50 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
textPreview: root?.innerText.slice(0, 1000) || "",
};
});
decisionCenterDemandText = await page.locator('[data-testid="decision-center-page"]').innerText({ timeout: 5000 });
decisionCenterDemandMetrics = await page.evaluate(() => {
const root = document.querySelector('[data-testid="decision-center-page"]') as HTMLElement | null;
const workspace = root?.querySelector('[data-testid="requirement-workspace"]') as HTMLElement | null;
const laneIds = ["external-goal", "internal-goal", "blocker", "parked", "authority"];
const lanes = Object.fromEntries(laneIds.map((id) => [id, Boolean(root?.querySelector(`[data-testid="requirement-lane-${id}"]`))]));
return {
workspaceVisible: Boolean(workspace),
editorVisible: Boolean(root?.querySelector('[data-testid="record-editor"]')),
filtersVisible: Boolean(root?.querySelector('[data-testid="decision-center-filters"]')),
filterButtons: root?.querySelectorAll('[data-testid^="requirement-filter-"]').length ?? 0,
lanes,
tableRows: root?.querySelectorAll('[data-testid="decision-center-record-table"] tbody tr').length ?? 0,
textPreview: root?.innerText.slice(0, 1000) || "",
};
});
await page.getByTestId("decision-tab-diary").click();
await page.waitForSelector('[data-testid="diary-editor"]', { timeout: 10000 });
await page.getByTestId("today-diary").click();
await page.waitForFunction(() => {
const input = document.querySelector('[data-testid="diary-date-input"]') as HTMLInputElement | null;
return /^\d{4}-\d{2}-\d{2}$/u.test(input?.value || "");
}, undefined, { timeout: 10000 });
await page.locator('[data-testid="diary-date-input"]').fill(decisionCenterDiaryDate);
await page.locator('[data-testid="diary-body-editor"]').fill(`# ${decisionCenterDiaryDate}\n${decisionCenterDiaryMarker}\n`);
await page.getByTestId("save-diary-button").click();
await page.waitForFunction((marker) => document.body.innerText.includes(String(marker)), decisionCenterDiaryMarker, { timeout: 30000 });
decisionCenterDiaryText = await page.locator('[data-testid="decision-center-page"]').innerText({ timeout: 5000 });
decisionCenterDiaryMetrics = await page.evaluate(({ date, marker }) => {
const root = document.querySelector('[data-testid="decision-center-page"]') as HTMLElement | null;
const dateInput = root?.querySelector('[data-testid="diary-date-input"]') as HTMLInputElement | null;
const bodyInput = root?.querySelector('[data-testid="diary-body-editor"]') as HTMLTextAreaElement | null;
const dateCards = Array.from(root?.querySelectorAll(`[data-testid="diary-entry-${date}"]`) ?? []);
return {
editorVisible: Boolean(root?.querySelector('[data-testid="diary-editor"]')),
todayButtonVisible: Boolean(root?.querySelector('[data-testid="today-diary"]')) && Boolean(root?.querySelector('[data-testid="today-diary-button"]')),
dateValue: dateInput?.value || "",
bodyValue: bodyInput?.value || "",
entryCards: root?.querySelectorAll('[data-testid^="diary-entry-"]').length ?? 0,
duplicateDateCards: dateCards.length,
selectedHasMarker: Boolean(root?.innerText.includes(String(marker))),
textPreview: root?.innerText.slice(0, 1000) || "",
};
}, { date: decisionCenterDiaryDate, marker: decisionCenterDiaryMarker });
const decisionCenterRecordId = String(decisionCenterE2eRecord?.body?.record?.id || "");
if (decisionCenterRecordId) {
decisionCenterDeleteResult = await page.evaluate(async (id) => {
@@ -2244,6 +2419,14 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
return { ok: response.ok, status: response.status, body: await response.json().catch(() => null) };
}, decisionCenterRecordId);
}
if (decisionCenterE2eGoalId) {
await page.evaluate(async (id) => {
await fetch(`/api/microservices/decision-center/proxy/api/records/${encodeURIComponent(String(id))}`, {
method: "DELETE",
credentials: "same-origin",
}).catch(() => null);
}, decisionCenterE2eGoalId);
}
}
if (needCodeQueue) {
await page.getByLabel("用户服务 子功能").getByRole("button", { name: "Code Queue" }).click();
@@ -3363,6 +3546,39 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
&& Number(decisionCenterMetrics.chatInputCount || 0) === 0
&& !decisionCenterText.includes("{\n"),
{ decisionCenterMetrics, decisionCenterE2eRecord, decisionCenterDeleteResult, decisionCenterTextPreview: decisionCenterText.slice(0, 1400) });
addSelectedCheck(checks, options, "frontend:decision-center-demand-management-visible",
decisionCenterDemandText.includes("需求管理工作区")
&& decisionCenterDemandText.includes("外部目标")
&& decisionCenterDemandText.includes("内部目标")
&& decisionCenterDemandText.includes("阻塞")
&& decisionCenterDemandText.includes("停放事项")
&& decisionCenterDemandText.includes("决议/实验/债务")
&& decisionCenterDemandText.includes("录入需求记录")
&& decisionCenterDemandMetrics.workspaceVisible === true
&& decisionCenterDemandMetrics.editorVisible === true
&& decisionCenterDemandMetrics.filtersVisible === true
&& Number(decisionCenterDemandMetrics.filterButtons || 0) >= 5
&& decisionCenterDemandMetrics.lanes?.["external-goal"] === true
&& decisionCenterDemandMetrics.lanes?.["internal-goal"] === true
&& decisionCenterDemandMetrics.lanes?.blocker === true
&& decisionCenterDemandMetrics.lanes?.parked === true
&& decisionCenterDemandMetrics.lanes?.authority === true
&& !decisionCenterDemandText.includes("{\n"),
{ decisionCenterDemandMetrics, decisionCenterDemandPreview: decisionCenterDemandText.slice(0, 1400) });
addSelectedCheck(checks, options, "frontend:decision-center-diary-visible",
decisionCenterDiaryText.includes("工作日记编辑台")
&& decisionCenterDiaryText.includes("日记筛选")
&& decisionCenterDiaryText.includes("按天条目")
&& decisionCenterDiaryText.includes("PostgreSQL / YYYY-MM/YYYY-MM-DD.md")
&& decisionCenterDiaryMetrics.editorVisible === true
&& decisionCenterDiaryMetrics.todayButtonVisible === true
&& decisionCenterDiaryMetrics.dateValue === "2099-12-30"
&& String(decisionCenterDiaryMetrics.bodyValue || "").includes("E2E diary marker")
&& Number(decisionCenterDiaryMetrics.entryCards || 0) >= 1
&& Number(decisionCenterDiaryMetrics.duplicateDateCards || 0) >= 1
&& decisionCenterDiaryMetrics.selectedHasMarker === true
&& !decisionCenterDiaryText.includes("{\n"),
{ decisionCenterDiaryMetrics, decisionCenterDiaryPreview: decisionCenterDiaryText.slice(0, 1400) });
addSelectedCheck(checks, options, "frontend:code-queue-integrated-visible", codeQueueTextLower.includes("code queue") && codeQueueText.includes("gpt-5.4-mini") && codeQueueText.includes("gpt-5.4") && codeQueueText.includes("gpt-5.5") && codeQueueText.includes("提交任务") && codeQueueText.includes("执行 Provider") && codeQueueText.includes("入队份数") && codeQueueText.includes("追加 prompt") && codeQueueText.includes("打断") && codeQueueTextLower.includes("查看 queue") && codeQueueText.includes("创建 queue") && codeQueueText.includes("合并 queue") && codeQueueOptions.some((text) => text.includes("All queues")) && codeQueueTracePlacement.firstChildIsTrace === true && codeQueueTracePlacement.noPageTopStatus === true && codeQueueTracePlacement.filterInsideTracePanel === true && codeQueueTracePlacement.taskSearchVisible === true && codeQueueTracePlacement.traceStatusVisible === true && codeQueueTracePlacement.markAllReadVisible === true && codeQueueGlobalStatus.activeMicroserviceVisible === true && codeQueueSidebarUpdateMetrics.hasRecentUpdateLabel === true && codeQueueHtmlGuard.rootAttrMissing === true && codeQueueHtmlGuard.sourceAttrMissing === true && codeQueueHtmlGuard.sourceNoBasePrompt === true && codeQueueSubmitQueueControl.tagName === "select" && codeQueueSubmitQueueControl.createButtonVisible === true && codeQueueSubmitQueueControl.mergeButtonVisible === true && codeQueueSubmitQueueControl.mergeSourceInlineMissing === true && codeQueueSubmitQueueControl.mergeDialogMissingBeforeClick === true && (codeQueueSubmitQueueControl.mergeButtonDisabled === true || (codeQueueSubmitQueueControl.mergeDialogVisible === true && codeQueueSubmitQueueControl.mergeDialogSelectVisible === true && Number(codeQueueSubmitQueueControl.mergeDialogSourceOptionCount || 0) > 1 && codeQueueSubmitQueueControl.mergeDialogSelectInsideSubmitForm !== true && codeQueueSubmitQueueControl.mergeDialogUsesCommonComponent === true && codeQueueSubmitQueueControl.mergeDialogDeleteNoteVisible === true)) && codeQueueSubmitQueueControl.oldInputMissing === true && codeQueueSubmitQueueControl.providerValue === "D601" && codeQueueSubmitQueueControl.cwdValue === "/workspace" && Array.isArray(codeQueueSubmitQueueControl.providerOptions) && codeQueueSubmitQueueControl.providerOptions.some((item: any) => item.value === "D601" && String(item.text || "").includes("/workspace")) && codeQueueSubmitQueueControl.maxAttemptsMax === "99" && codeQueueSubmitQueueControl.maxAttemptsValue === "99" && codeQueueSubmitQueueControl.moveQueueVisible === true && codeQueuePromptDefaultEmpty === true && codeQueueSubmitGuard.batchRowVisible === true && codeQueueSubmitGuard.checkboxVisible === true && codeQueueSubmitGuard.disabledBeforeConfirm === true && codeQueueSubmitGuard.enabledAfterConfirm === true && codeQueueSubmitGuard.waitElementMissingBeforeSubmit === true && codeQueueScrollbarMetrics.transcriptThin === true && codeQueueScrollbarMetrics.toolHorizontalHidden === true && (codeQueueSwitchMetrics.optionCount <= 1 || codeQueueSwitchMetrics.switched === true) && codeQueueTextLower.includes("attempts") && codeQueueText.includes("仅 UniDesk frontend 代理访问") && (codeQueueTaskCount === 0 || codeQueueOutputText.includes("Submitted prompt")), { codeQueueTaskCount, codeQueueOptions, codeQueueSwitchMetrics, codeQueueSubmitQueueControl, codeQueueSubmitGuard, codeQueueScrollbarMetrics, codeQueuePromptDefaultEmpty, codeQueueTracePlacement, codeQueueGlobalStatus, codeQueueSidebarUpdateMetrics, codeQueueHtmlGuard, codeQueueOutputPreview: codeQueueOutputText.slice(0, 900), codeQueueTextPreview: codeQueueText.slice(0, 1400) });
const expectedFrontendCodeQueueProvider = isDevFrontendTarget() ? "D601-dev" : "D601";
const expectedFrontendCodeQueueWorkdir = isDevFrontendTarget() ? "/workspace-dev" : "/workspace";