test(pi): separate submit rejection proof
This commit is contained in:
1 parent
5f0ef761ea
commit
e3debc9b33
2 files changed
+35
-17
No files matched your search
@@ -98,8 +98,11 @@
|
|||||||
persistent preparation error. Existing runtime/session recovery state remains
|
persistent preparation error. Existing runtime/session recovery state remains
|
||||||
reserved for preparation, hydration, worker, and session failures.
|
reserved for preparation, hydration, worker, and session failures.
|
||||||
- Extended the final packaged proof with a Works-shaped endpoint role canary and
|
- 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
|
a real Renderer reject/edit/retry/settle flow. The endpoint rejects leading
|
||||||
provider modes are protected by a focused wiring regression.
|
`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.
|
- Packaging and final artifact/product proof remain pending.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
@@ -115,6 +118,12 @@
|
|||||||
- `corepack pnpm run build:vite` — Pass; Renderer/Main/Preload/utility built,
|
- `corepack pnpm run build:vite` — Pass; Renderer/Main/Preload/utility built,
|
||||||
with existing chunk/dynamic-import warnings.
|
with existing chunk/dynamic-import warnings.
|
||||||
- `corepack pnpm run test:electron:windows` — Pass: 2 files / 4 tests.
|
- `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
|
## Follow-ups
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import path from 'node:path';
|
|||||||
import { promisify } from 'node:util';
|
import { promisify } from 'node:util';
|
||||||
|
|
||||||
import type { CodingProductComposition } from '../../api/coding-product-services';
|
import type { CodingProductComposition } from '../../api/coding-product-services';
|
||||||
|
import { CodingConversationServiceError } from '../conversation-service';
|
||||||
import { getRecentLogs } from '../../utils/logger';
|
import { getRecentLogs } from '../../utils/logger';
|
||||||
import { createCodingConversationStore } from '../../coding-projects/conversation-store';
|
import { createCodingConversationStore } from '../../coding-projects/conversation-store';
|
||||||
import { createCodingProjectAgent } from '../../coding-projects/project-config';
|
import { createCodingProjectAgent } from '../../coding-projects/project-config';
|
||||||
@@ -57,7 +58,7 @@ type ProviderRequest = {
|
|||||||
toolNames: string[];
|
toolNames: string[];
|
||||||
hasToolResult: boolean;
|
hasToolResult: boolean;
|
||||||
firstMessageRole: string | null;
|
firstMessageRole: string | null;
|
||||||
outcome: 'accepted' | 'controlled_rejection' | 'developer_role_rejection';
|
outcome: 'accepted' | 'developer_role_rejection';
|
||||||
};
|
};
|
||||||
|
|
||||||
type HeldProviderResponse = {
|
type HeldProviderResponse = {
|
||||||
@@ -104,6 +105,8 @@ type ProxyCompositionRun = {
|
|||||||
projectId: string;
|
projectId: string;
|
||||||
projectPath: string;
|
projectPath: string;
|
||||||
hostToken: string;
|
hostToken: string;
|
||||||
|
originalAcceptPrompt: CodingProductComposition['conversations']['acceptPrompt'];
|
||||||
|
submissionInjection: { definiteRejections: number };
|
||||||
activeStatus?: PiReleaseProxyCompositionStatus;
|
activeStatus?: PiReleaseProxyCompositionStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -448,7 +451,6 @@ async function startLocalProofProvider(mode: ProofProviderMode): Promise<LocalPr
|
|||||||
const held = new Set<HeldProviderResponse>();
|
const held = new Set<HeldProviderResponse>();
|
||||||
let closed = false;
|
let closed = false;
|
||||||
let closeFlight: Promise<void> | null = null;
|
let closeFlight: Promise<void> | null = null;
|
||||||
let controlledSubmitRejectionIssued = false;
|
|
||||||
const server: Server = createServer(async (request, response) => {
|
const server: Server = createServer(async (request, response) => {
|
||||||
response.once('error', () => undefined);
|
response.once('error', () => undefined);
|
||||||
try {
|
try {
|
||||||
@@ -486,16 +488,6 @@ async function startLocalProofProvider(mode: ProofProviderMode): Promise<LocalPr
|
|||||||
rejectProofRequest(response, 'developer role is unsupported by the controlled endpoint');
|
rejectProofRequest(response, 'developer role is unsupported by the controlled endpoint');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mode === 'submit-rejection'
|
|
||||||
&& role === 'parent'
|
|
||||||
&& !toolResult
|
|
||||||
&& !controlledSubmitRejectionIssued) {
|
|
||||||
controlledSubmitRejectionIssued = true;
|
|
||||||
providerRequest.outcome = 'controlled_rejection';
|
|
||||||
rejectProofRequest(response, 'controlled definite model rejection');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode === 'resilience') {
|
if (mode === 'resilience') {
|
||||||
if (role === 'child') {
|
if (role === 'child') {
|
||||||
if (toolResult) respondWithText(response, model, 'RESILIENCE_CHILD_COMPLETE');
|
if (toolResult) respondWithText(response, model, 'RESILIENCE_CHILD_COMPLETE');
|
||||||
@@ -914,9 +906,7 @@ async function proxyCompositionStatus(
|
|||||||
systemRoleRequests: run.provider.requests.filter(({ firstMessageRole }) => (
|
systemRoleRequests: run.provider.requests.filter(({ firstMessageRole }) => (
|
||||||
firstMessageRole === 'system'
|
firstMessageRole === 'system'
|
||||||
)).length,
|
)).length,
|
||||||
controlledDefiniteRejections: run.provider.requests.filter(({ outcome }) => (
|
controlledDefiniteRejections: run.submissionInjection.definiteRejections,
|
||||||
outcome === 'controlled_rejection'
|
|
||||||
)).length,
|
|
||||||
};
|
};
|
||||||
const parent = processInspection.processes
|
const parent = processInspection.processes
|
||||||
.filter(({ role }) => role === 'parent')
|
.filter(({ role }) => role === 'parent')
|
||||||
@@ -1342,6 +1332,7 @@ export async function runFinalAsarExtensionProof(): Promise<PiReleaseExtensionPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function cleanupProxyCompositionRun(run: ProxyCompositionRun): Promise<void> {
|
async function cleanupProxyCompositionRun(run: ProxyCompositionRun): Promise<void> {
|
||||||
|
run.composition.conversations.acceptPrompt = run.originalAcceptPrompt;
|
||||||
run.provider.releaseAll();
|
run.provider.releaseAll();
|
||||||
await run.composition.projects.removeProject(run.projectId).catch(() => undefined);
|
await run.composition.projects.removeProject(run.projectId).catch(() => undefined);
|
||||||
await run.provider.close().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.',
|
prompt: 'Follow the controlled loopback Provider and complete its subagent request.',
|
||||||
skillIds: [],
|
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 = {
|
proxyCompositionRun = {
|
||||||
composition: input.composition,
|
composition: input.composition,
|
||||||
provider,
|
provider,
|
||||||
projectId,
|
projectId,
|
||||||
projectPath: input.projectPath,
|
projectPath: input.projectPath,
|
||||||
hostToken,
|
hostToken,
|
||||||
|
originalAcceptPrompt,
|
||||||
|
submissionInjection,
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
projectId,
|
projectId,
|
||||||
|
|||||||
Reference in new issue
Block a user