mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-26 18:31:34 +01:00
Merge branch 'codex/work-folders-remote-recovery-refresh' into codex/work-folders-session-compat-refresh
* codex/work-folders-remote-recovery-refresh: fix(runner): preserve v2 event metadata and reject nonretryable campaign failures fix(runner): preserve exact Claude model selectors during ACP admission test(runner): serve goal reads while holding passive completion notices fix(ci): validate shared Cloud image contexts throughout the stack
This commit is contained in:
commit
b48689cb00
9 files changed
+168
-62
No files matched your search
@@ -2,6 +2,7 @@ import { readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
PRP_V1_EVENT_TYPES,
|
||||
PRP_V2_EVENT_TYPES,
|
||||
REDACTED_EVENT_VALUE,
|
||||
redactAgentAdapterConfig,
|
||||
redactEventPayload,
|
||||
@@ -23,6 +24,36 @@ describe("redaction", () => {
|
||||
expect([...PRP_V1_EVENT_TYPES]).toEqual(schema.properties.eventType.enum);
|
||||
});
|
||||
|
||||
it("keeps the discriminator allowlist in exact PRP v2 schema parity", () => {
|
||||
const schema = JSON.parse(readFileSync(new URL(
|
||||
"../../../packages/paperclip-runner/protocol/schemas/event-v2.schema.json",
|
||||
import.meta.url,
|
||||
), "utf8")) as { properties: { eventType: { enum: string[] } } };
|
||||
expect([...PRP_V2_EVENT_TYPES].sort()).toEqual(schema.properties.eventType.enum.sort());
|
||||
});
|
||||
|
||||
it("preserves v2 goal envelopes while redacting secrets and mismatched versions", () => {
|
||||
for (const eventType of PRP_V2_EVENT_TYPES) {
|
||||
const envelope = {
|
||||
schema: "paperclip.prp.event.v2", schemaVersion: 2, eventType,
|
||||
payload: { apiKey: "secret", opaque: "aaa.bbb.ccc" },
|
||||
};
|
||||
expect(sanitizeRecord(envelope)).toEqual({
|
||||
...envelope,
|
||||
payload: { apiKey: REDACTED_EVENT_VALUE, opaque: REDACTED_EVENT_VALUE },
|
||||
});
|
||||
}
|
||||
for (const envelope of [
|
||||
{ schema: "paperclip.prp.event.v1", schemaVersion: 1, eventType: "session.goal.snapshot" },
|
||||
{ schema: "paperclip.prp.event.v2", schemaVersion: 1, eventType: "session.goal.snapshot" },
|
||||
{ schema: "paperclip.prp.event.v1", schemaVersion: 2, eventType: "session.goal.snapshot" },
|
||||
{ schema: "paperclip.prp.event.v2", schemaVersion: 2, eventType: "aaa.bbb.ccc" },
|
||||
{ schema: "paperclip.prp.event.v3", schemaVersion: 3, eventType: "session.goal.snapshot" },
|
||||
]) {
|
||||
expect(sanitizeRecord(envelope).eventType).toBe(REDACTED_EVENT_VALUE);
|
||||
}
|
||||
});
|
||||
|
||||
it("preserves every discriminator in the cross-language replay stream", () => {
|
||||
const fixture = JSON.parse(
|
||||
readFileSync(
|
||||
|
||||
+19
-4
@@ -110,6 +110,7 @@ export const PAPERCLIP_PUBLIC_SCHEMA_IDS = new Set([
|
||||
"paperclip.prp.command.v1",
|
||||
"paperclip.prp.contract_manifest.v1",
|
||||
"paperclip.prp.event.v1",
|
||||
"paperclip.prp.event.v2",
|
||||
"paperclip.prp.fixture.v1",
|
||||
"paperclip.prp.identity.v1",
|
||||
"paperclip.prp.semantic_tool.v1",
|
||||
@@ -194,7 +195,7 @@ export const PAPERCLIP_PUBLIC_SCHEMA_IDS = new Set([
|
||||
// Keep this closed catalog aligned with PRP v1's event.schema.json. These
|
||||
// values are public protocol discriminators, but their dotted shape overlaps
|
||||
// the deliberately broad JWT heuristic. They are exempt only in the
|
||||
// discriminator field of a PRP v1 event envelope; the same string anywhere
|
||||
// discriminator field of a supported PRP event envelope; the same string anywhere
|
||||
// else remains subject to redaction.
|
||||
export const PRP_V1_EVENT_TYPES = new Set([
|
||||
"runner.connected",
|
||||
@@ -303,6 +304,17 @@ export const PRP_V1_EVENT_TYPES = new Set([
|
||||
"issue.status.decision.superseded",
|
||||
"run.terminal",
|
||||
]);
|
||||
// V2 removes backpressure and semantic reconciliation, and adds goal events.
|
||||
// Exact parity with both protocol schemas is enforced by redaction.test.ts.
|
||||
export const PRP_V2_EVENT_TYPES = new Set([
|
||||
...[...PRP_V1_EVENT_TYPES].filter(
|
||||
(type) => type !== "runner.backpressure" && type !== "semantic_tool.reconciled",
|
||||
),
|
||||
"session.capabilities.updated",
|
||||
"session.goal.snapshot",
|
||||
"session.goal.updated",
|
||||
"session.goal.cleared",
|
||||
]);
|
||||
const NATIVE_RUN_SPAN_SCHEMA = "paperclip.run-performance-span.v1";
|
||||
const NATIVE_RUN_SPAN_FIELDS = ["span", "parentSpan"] as const;
|
||||
const NATIVE_RUN_SPAN_NAMES = new Set([
|
||||
@@ -843,10 +855,13 @@ function isKnownPrpEventDiscriminator(
|
||||
): value is string {
|
||||
return (
|
||||
key === "eventType" &&
|
||||
container.schema === "paperclip.prp.event.v1" &&
|
||||
container.schemaVersion === 1 &&
|
||||
typeof value === "string" &&
|
||||
PRP_V1_EVENT_TYPES.has(value)
|
||||
((container.schema === "paperclip.prp.event.v1" &&
|
||||
container.schemaVersion === 1 &&
|
||||
PRP_V1_EVENT_TYPES.has(value)) ||
|
||||
(container.schema === "paperclip.prp.event.v2" &&
|
||||
container.schemaVersion === 2 &&
|
||||
PRP_V2_EVENT_TYPES.has(value)))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user