mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-03 17:51:58 +01:00
fix(testops): reuse retained-key owner and document gap readback
Use the existing archive-key helpers and state that recovered gap bundles require gap-aware GET reconciliation. Frozen payload bytes and original grades stay unchanged. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
b4e5e16469
commit
d91d18efea
3 files changed
+10
-3
No files matched your search
@@ -3407,7 +3407,10 @@ any upload archive. Private originals, screenshots and traces stay private.
|
||||
|
||||
Review the immutable payload and its file hashes before an authorized upload to
|
||||
the original jobrun. Persist a once-intent before transmission. After an ambiguous
|
||||
response, reconcile with GET requests; do not resend or regenerate UUIDs. Final
|
||||
response, reconcile with manual GET requests or an independently reviewed,
|
||||
gap-aware read-only check; do not resend or regenerate UUIDs. The existing
|
||||
`verify-upload` CLI accepts strict original outcomes only. It cannot verify the
|
||||
separate BROKEN gap shape and must not be used for this recovery bundle. Final
|
||||
coverage must match all selected case IDs and preserve the separate gap count.
|
||||
This mode prepares data only. It does not upload, start jobs, reopen launches,
|
||||
change credentials, or change evaluation and evidence limits.
|
||||
@@ -8,6 +8,8 @@ import { hash, validateSelection, catalogDefinition, model } from "./chat-comple
|
||||
import type { PilotContext, PilotSelection } from "./chat-completion-testops-contract.mjs";
|
||||
import type { RunnerE2EResult } from "./types.js";
|
||||
import { findSecretLeakInJsonValues } from "./redaction.js";
|
||||
import { privateArtifactKey } from "./private-history.js";
|
||||
import { manualCellKind } from "./manual-private-retention.js";
|
||||
|
||||
export async function mergeCatalogProjections(root: string, output: string, selection: PilotSelection, context: PilotContext) {
|
||||
if (context.catalog !== "full") throw new Error("Full catalog context required");
|
||||
@@ -85,7 +87,7 @@ export async function prepareRetainedCatalogReport(root: string, output: string,
|
||||
for (const gap of disposition.gaps) {
|
||||
if (!keys(gap, ["executionId", "archiveKey", "archiveStatus"]) || gaps.has(gap.executionId)
|
||||
|| !selected.some(row => row.executionId === gap.executionId) || gap.archiveStatus !== "not_found"
|
||||
|| gap.archiveKey !== `runner-e2e-private/bounded-v1/campaigns/gha-${context.runId}-1/manual-cell-${hash(gap.executionId)}.zip`) throw new Error("Invalid reporting gap");
|
||||
|| gap.archiveKey !== privateArtifactKey(manualCellKind(gap.executionId), context.runId)) throw new Error("Invalid reporting gap");
|
||||
gaps.add(gap.executionId);
|
||||
}
|
||||
const stat = await lstat(root);
|
||||
|
||||
@@ -6,6 +6,8 @@ import os from 'node:os';
|
||||
import * as aggregate from './chat-full-catalog-testops-merge.js';
|
||||
import {hash,model} from './chat-completion-testops-contract.mjs';
|
||||
import {fullCatalogCases,catalogTargetSha} from './chat-full-catalog-testops-manifest.mjs';
|
||||
import {privateArtifactKey} from './private-history.js';
|
||||
import {manualCellKind} from './manual-private-retention.js';
|
||||
const roots:string[]=[];
|
||||
afterEach(async()=>{await Promise.all(roots.splice(0).map(root=>rm(root,{recursive:true,force:true})));});
|
||||
const context={catalog:'full' as const,runId:'123',attempt:'1',workflowSha:'a'.repeat(40),targetSha:catalogTargetSha};
|
||||
@@ -22,7 +24,7 @@ async function fixture(t:any){
|
||||
for(const [name,data] of files)await writeFile(path.join(dir,name),data);
|
||||
await writeFile(path.join(dir,'binding.json'),JSON.stringify({schema:'paperclip.chat-completion-testops-export/v1',...context,campaignId:'gha-123-1',executionIds:[row.executionId],files:[...files].map(([name,data])=>({path:name,bytes:data.length,sha256:hash(data)})),privateEvidence:[{executionId:row.executionId,requiredEvidenceComplete:passed,finalScreenshot:passed?{sha256:'e'.repeat(64),bytes:24}:null}]}));
|
||||
}
|
||||
const disposition={schema:'paperclip.chat-catalog-retained-disposition/v1',origin:{...context,projectId:1,planId:102,jobId:100,launchId:12,allureJobRunId:'77'},selectionSha256:hash(JSON.stringify(selection,null,2)),upstream:{status:'completed',jobsSha256:'b'.repeat(64)},custodySha256:'c'.repeat(64),gaps:[{executionId:cases[2].executionId,archiveKey:`runner-e2e-private/bounded-v1/campaigns/gha-123-1/manual-cell-${hash(cases[2].executionId)}.zip`,archiveStatus:'not_found'}]};
|
||||
const disposition={schema:'paperclip.chat-catalog-retained-disposition/v1',origin:{...context,projectId:1,planId:102,jobId:100,launchId:12,allureJobRunId:'77'},selectionSha256:hash(JSON.stringify(selection,null,2)),upstream:{status:'completed',jobsSha256:'b'.repeat(64)},custodySha256:'c'.repeat(64),gaps:[{executionId:cases[2].executionId,archiveKey:privateArtifactKey(manualCellKind(cases[2].executionId),context.runId),archiveStatus:'not_found'}]};
|
||||
return {root,input,selection,disposition,context,output:path.join(root,'report')};
|
||||
}
|
||||
async function prepare(f:any){return (aggregate.prepareRetainedCatalogReport ?? aggregate.mergeCatalogProjections)(f.input,f.output,f.selection,f.context,f.disposition,{kind:'operator',revisionSha:'d'.repeat(40)});}
|
||||
|
||||
Reference in new issue
Block a user