From e3debc9b3337ff20594997f445500e19c288dc64 Mon Sep 17 00:00:00 2001 From: brother7 <7brother7@gmail.com> Date: Tue, 25 Aug 2026 15:00:52 +0800 Subject: [PATCH] test(pi): separate submit rejection proof --- ...0825-pi-submit-rejected-hotfix-9f3c7a62.md | 13 ++++++- electron/coding-runtime/pi/release-proof.ts | 39 ++++++++++++------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/.project-docs/30-worklog/tasks/20260825-pi-submit-rejected-hotfix-9f3c7a62.md b/.project-docs/30-worklog/tasks/20260825-pi-submit-rejected-hotfix-9f3c7a62.md index 7fdcf39..110d5b5 100644 --- a/.project-docs/30-worklog/tasks/20260825-pi-submit-rejected-hotfix-9f3c7a62.md +++ b/.project-docs/30-worklog/tasks/20260825-pi-submit-rejected-hotfix-9f3c7a62.md @@ -98,8 +98,11 @@ persistent preparation error. Existing runtime/session recovery state remains reserved for preparation, hydration, worker, and session failures. - Extended the final packaged proof with a Works-shaped endpoint role canary and - a real Renderer reject/edit/retry/settle flow. The extension and proxy proof - provider modes are protected by a focused wiring regression. + a real Renderer reject/edit/retry/settle flow. The endpoint rejects leading + `developer`, while an E2E-only one-shot Main service rejection exercises the + distinct definite-POST branch before the retry reaches the real Pi runtime. + The extension and proxy proof provider modes are protected by a focused + wiring regression. - Packaging and final artifact/product proof remain pending. ## Verification @@ -115,6 +118,12 @@ - `corepack pnpm run build:vite` — Pass; Renderer/Main/Preload/utility built, with existing chunk/dynamic-import warnings. - `corepack pnpm run test:electron:windows` — Pass: 2 files / 4 tests. +- The first packaged proof attempt correctly showed that a Provider HTTP 400 + after Pi prompt preflight is an accepted-run failure, not a definite POST + rejection; it did not restore the draft and the proof failed. The proof was + corrected to keep role rejection and definite submission injection separate. +- After that correction, focused, typecheck, lint, full unit, `build:vite`, and + Windows Electron E2E were rerun and passed with the same counts/warnings. ## Follow-ups diff --git a/electron/coding-runtime/pi/release-proof.ts b/electron/coding-runtime/pi/release-proof.ts index 01be38a..9855383 100644 --- a/electron/coding-runtime/pi/release-proof.ts +++ b/electron/coding-runtime/pi/release-proof.ts @@ -6,6 +6,7 @@ import path from 'node:path'; import { promisify } from 'node:util'; import type { CodingProductComposition } from '../../api/coding-product-services'; +import { CodingConversationServiceError } from '../conversation-service'; import { getRecentLogs } from '../../utils/logger'; import { createCodingConversationStore } from '../../coding-projects/conversation-store'; import { createCodingProjectAgent } from '../../coding-projects/project-config'; @@ -57,7 +58,7 @@ type ProviderRequest = { toolNames: string[]; hasToolResult: boolean; firstMessageRole: string | null; - outcome: 'accepted' | 'controlled_rejection' | 'developer_role_rejection'; + outcome: 'accepted' | 'developer_role_rejection'; }; type HeldProviderResponse = { @@ -104,6 +105,8 @@ type ProxyCompositionRun = { projectId: string; projectPath: string; hostToken: string; + originalAcceptPrompt: CodingProductComposition['conversations']['acceptPrompt']; + submissionInjection: { definiteRejections: number }; activeStatus?: PiReleaseProxyCompositionStatus; }; @@ -448,7 +451,6 @@ async function startLocalProofProvider(mode: ProofProviderMode): Promise(); let closed = false; let closeFlight: Promise | null = null; - let controlledSubmitRejectionIssued = false; const server: Server = createServer(async (request, response) => { response.once('error', () => undefined); try { @@ -486,16 +488,6 @@ async function startLocalProofProvider(mode: ProofProviderMode): Promise ( firstMessageRole === 'system' )).length, - controlledDefiniteRejections: run.provider.requests.filter(({ outcome }) => ( - outcome === 'controlled_rejection' - )).length, + controlledDefiniteRejections: run.submissionInjection.definiteRejections, }; const parent = processInspection.processes .filter(({ role }) => role === 'parent') @@ -1342,6 +1332,7 @@ export async function runFinalAsarExtensionProof(): Promise { + run.composition.conversations.acceptPrompt = run.originalAcceptPrompt; run.provider.releaseAll(); await run.composition.projects.removeProject(run.projectId).catch(() => undefined); await run.provider.close().catch(() => undefined); @@ -1400,12 +1391,30 @@ export async function startFinalAsarProxyCompositionProof(input: { prompt: 'Follow the controlled loopback Provider and complete its subagent request.', skillIds: [], }); + const originalAcceptPrompt = input.composition.conversations.acceptPrompt + .bind(input.composition.conversations); + const submissionInjection = { definiteRejections: 0 }; + let rejectNextSubmission = true; + input.composition.conversations.acceptPrompt = async (promptInput) => { + if (rejectNextSubmission) { + rejectNextSubmission = false; + submissionInjection.definiteRejections += 1; + throw new CodingConversationServiceError( + 503, + 'CODING_MODEL_UNAVAILABLE', + 'Controlled packaged submission rejection', + ); + } + return await originalAcceptPrompt(promptInput); + }; proxyCompositionRun = { composition: input.composition, provider, projectId, projectPath: input.projectPath, hostToken, + originalAcceptPrompt, + submissionInjection, }; return { projectId,