mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-08 11:13:44 +02:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The Rust runner now owns validated, scoped ACPX reducer events and safe session suspension > - Durable PRP transport must receive provider-neutral events rather than sidecar-native envelopes > - Semantic calls and questions must retain the exact run, session, turn, item, and provider-request authority used by the durable command stream > - Terminal, result, assistant, process, and diagnostic events also need one reviewed projection boundary > - Permission requests remain impossible under the pinned Codex policy and must fail closed if they reach projection > - This pull request adds only that package-local projection without selecting ACPX in runnerd ## Linked Issues or Issue Description Refs #12422 ## What Changed - Add a validated durable ACPX event projection context bound to one run, normalized session, turn, and item. - Pass already normalized activity events through without reintroducing provider-native envelopes. - Project authorized tool calls into canonical semantic input receipts with exact correlation and content digests. - Project structured questions into provider-neutral `paperclip.runtime_request.v2` events. - Preserve both the public projected request identity and the original provider request identity so responses resolve the exact sidecar request. - Project dynamic semantic operation results as `semantic_tool.result`; only reserved finish/block operations may propose the run result. - Project semantic completion results into `run.result.proposed`. - Project terminal-flushed assistant messages on the final channel and turn terminal states into existing provider-neutral event families. - Project sanitized process metadata and diagnostics into bounded harness diagnostics. - Validate runtime-request origins against their strict durable shape and fall back from empty optional titles to a valid question prompt. - Reject invalid identities, projected-identity collisions, unstable semantic receipt identities, permission requests, and cross-turn projection fail closed. - Add integration coverage across reducer event families, correlation, identity validation, projected question resolution, and pinned-policy denial. - Document the durable projection boundary. - Do not change dependencies, lockfiles, workflows, runnerd selection, server behavior, UI, or migrations. ## Verification - Replay base: `80639f4f69c8938eb74bdc0833df93e0ed91dab3` (`master` after #12422 merged). - Exact replay head: `3cb29581d2bcbc4b47f8069baffd721c6ce4e444`. - Stable patch ID: `92910b56575e67ae83960177d467a565019ba282`. - The exact delta is 22 files, 1,206 additions, and 59 deletions, all in `packages/paperclip-runner`; it contains no lockfile, workflow, server, UI, dependency, or migration change. - `git diff --check` and the Cargo formatting check pass on the replayed delta. - Exact-head GitHub Actions run `33372209037` (attempt 2): **PASSED** with 23/23 jobs passed. - Greptile reviewed exact head `3cb29581d2bcbc4b47f8069baffd721c6ce4e444`: **5/5**, with zero unresolved review threads. - Superagent, contributor trust, Socket, and Snyk security checks: **PASSED**. - No local test result is claimed. GitHub Actions is the authoritative verification environment for this replayed revision. ## Risks - This function accepts reducer output, not raw sidecar frames. Callers must preserve the existing scope-first decode and reduction order. - Semantic input includes the already sanitized provider input while its content receipt uses the same canonical digest. - Structured input preserves the validated provider-neutral question set and sanitized origin. - Noncanonical provider request identities are deterministically projected for PRP while the original identity remains authoritative for the sidecar resolution command. - Existing PRP v1 identifiers remain schema-compatible; the only public ID-schema change widens turn/item limits from 160 to 240 characters. The internal ACPX sidecar wire schema now mirrors the stable IDs its Rust transport already enforced. - The projector verifies event-carried terminal and assistant turn identifiers against the durable context. - No production path invokes this projector in this pull request. Durable command execution remains the next slice. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex with GPT-5.6, agentic reasoning, tool use, and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used with version and capability details - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have linked the preceding public PR or described the issue in-PR - [x] I have not referenced internal or instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal Paperclip ticket id - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge
193 lines
11 KiB
JSON
193 lines
11 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://paperclip.dev/schemas/prp/v1/event.schema.json",
|
|
"title": "PRP native event",
|
|
"type": "object",
|
|
"required": [
|
|
"schema",
|
|
"sourceEventId",
|
|
"sourceSeq",
|
|
"sourceInstanceId",
|
|
"sourceKind",
|
|
"runId",
|
|
"eventType",
|
|
"schemaVersion",
|
|
"priority",
|
|
"emittedAt",
|
|
"payload"
|
|
],
|
|
"properties": {
|
|
"schema": { "const": "paperclip.prp.event.v1" },
|
|
"sourceEventId": { "type": "string", "minLength": 1, "maxLength": 160 },
|
|
"sourceSeq": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 },
|
|
"sourceInstanceId": { "type": "string", "minLength": 1, "maxLength": 160 },
|
|
"sourceKind": { "enum": ["runner", "control_plane"] },
|
|
"runId": { "type": "string", "minLength": 1, "maxLength": 160 },
|
|
"normalizedSessionId": { "type": "string", "minLength": 1, "maxLength": 160 },
|
|
"turnId": { "type": "string", "minLength": 1, "maxLength": 240 },
|
|
"itemId": { "type": "string", "minLength": 1, "maxLength": 240 },
|
|
"eventType": {
|
|
"enum": [
|
|
"runner.connected", "runner.reconnected", "runner.reconciled", "runner.disconnected", "runner.draining", "runner.backpressure", "runner.suspending", "runner.suspended", "runner.stopped", "runner.diagnostic",
|
|
"runtime.phase.changed", "sandbox.metric", "workspace.ready", "workspace.change.updated", "workspace.diff.recorded", "workspace.file.referenced",
|
|
"harness.starting", "harness.ready", "harness.exited", "harness.diagnostic",
|
|
"plan.updated",
|
|
"tool.execution.started", "tool.execution.progressed", "tool.execution.completed",
|
|
"research.started", "research.progressed", "research.completed",
|
|
"delegation.started", "delegation.updated", "delegation.completed",
|
|
"model.route.changed", "model.verification.updated", "context.compacted",
|
|
"artifact.viewed", "artifact.generated", "review.mode.changed",
|
|
"hook.started", "hook.completed", "memory.citation.referenced",
|
|
"safety.review.started", "safety.review.completed", "terminal.input.sent",
|
|
"wait.started", "wait.completed", "provider.notice.recorded",
|
|
"session.starting", "session.started", "session.resuming", "session.resumed", "session.reconciled", "session.updated", "session.closed", "session.failed",
|
|
"turn.submitted", "turn.accepted", "turn.started", "turn.completed", "turn.failed", "turn.interrupted", "turn.cancelled",
|
|
"item.started", "item.delta", "item.completed", "item.failed", "usage.reported",
|
|
"semantic_tool.input", "semantic_tool.result", "semantic_tool.reconciled",
|
|
"mcp_app.discovered", "mcp_app.resource.resolved", "mcp_app.initializing", "mcp_app.ready", "mcp_app.tool_input", "mcp_app.tool_result", "mcp_app.action.requested", "mcp_app.action.resolved", "mcp_app.host_context.changed", "mcp_app.failed", "mcp_app.teardown",
|
|
"runtime_request.created", "runtime_request.resolved", "runtime_request.expired", "runtime_request.cancelled",
|
|
"interaction.request.proposed", "interaction.request.materialized", "interaction.request.rejected", "interaction.response.progressed", "interaction.response.resolved", "interaction.response.delivered",
|
|
"run.attached", "run.detached", "run.result.proposed", "run.result.accepted", "run.result.rejected",
|
|
"attention.request.proposed", "attention.request.routed", "attention.request.resolved", "attention.request.expired", "attention.request.superseded",
|
|
"work.assessment.recorded", "issue.status.decision.recorded", "issue.status.decision.applied", "issue.status.decision.rejected", "issue.status.decision.superseded",
|
|
"run.terminal"
|
|
]
|
|
},
|
|
"schemaVersion": { "const": 1 },
|
|
"priority": { "enum": [0, 1, 2] },
|
|
"emittedAt": { "type": "string", "format": "date-time" },
|
|
"observedAt": { "type": "string", "format": "date-time" },
|
|
"payload": {
|
|
"type": "object",
|
|
"properties": {
|
|
"channel": { "enum": ["progress", "final", "summary", "detail", "unknown"] },
|
|
"providerPhase": { "type": "string" },
|
|
"providerMethod": { "type": "string" }
|
|
},
|
|
"additionalProperties": true
|
|
},
|
|
"debug": { "type": "object", "additionalProperties": true }
|
|
},
|
|
"allOf": [
|
|
{ "if": { "properties": { "eventType": { "const": "plan.updated" } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/plan" } } } },
|
|
{ "if": { "properties": { "eventType": { "enum": ["tool.execution.started", "tool.execution.progressed", "tool.execution.completed"] } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/toolExecution" } } } },
|
|
{ "if": { "properties": { "eventType": { "enum": ["research.started", "research.progressed", "research.completed"] } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/research" } } } },
|
|
{ "if": { "properties": { "eventType": { "enum": ["delegation.started", "delegation.updated", "delegation.completed"] } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/delegation" } } } },
|
|
{ "if": { "properties": { "eventType": { "const": "model.route.changed" } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/modelRoute" } } } },
|
|
{ "if": { "properties": { "eventType": { "const": "model.verification.updated" } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/modelVerification" } } } },
|
|
{ "if": { "properties": { "eventType": { "const": "context.compacted" } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/contextCompacted" } } } },
|
|
{ "if": { "properties": { "eventType": { "const": "artifact.viewed" } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/artifactViewed" } } } },
|
|
{ "if": { "properties": { "eventType": { "const": "artifact.generated" } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/artifactGenerated" } } } },
|
|
{ "if": { "properties": { "eventType": { "const": "review.mode.changed" } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/reviewMode" } } } },
|
|
{ "if": { "properties": { "eventType": { "enum": ["hook.started", "hook.completed"] } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/hook" } } } },
|
|
{ "if": { "properties": { "eventType": { "const": "memory.citation.referenced" } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/memoryCitation" } } } },
|
|
{ "if": { "properties": { "eventType": { "enum": ["safety.review.started", "safety.review.completed"] } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/safetyReview" } } } },
|
|
{ "if": { "properties": { "eventType": { "const": "terminal.input.sent" } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/terminalInput" } } } },
|
|
{ "if": { "properties": { "eventType": { "enum": ["wait.started", "wait.completed"] } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/wait" } } } },
|
|
{ "if": { "properties": { "eventType": { "const": "provider.notice.recorded" } } }, "then": { "properties": { "payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/provider-event.schema.json#/$defs/providerNotice" } } } },
|
|
{
|
|
"if": { "properties": { "eventType": { "const": "workspace.file.referenced" } } },
|
|
"then": {
|
|
"properties": {
|
|
"payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/workspace-file-reference.schema.json" }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"if": { "properties": { "eventType": { "enum": ["workspace.change.updated", "workspace.diff.recorded"] } } },
|
|
"then": {
|
|
"properties": {
|
|
"payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/workspace-diff.schema.json" }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"if": { "properties": { "eventType": { "const": "workspace.diff.recorded" } } },
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"allOf": [
|
|
{ "$ref": "https://paperclip.dev/schemas/prp/v1/workspace-diff.schema.json" },
|
|
{ "type": "object", "properties": { "complete": { "const": true } } }
|
|
]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"if": { "properties": { "eventType": { "enum": ["semantic_tool.input", "mcp_app.tool_input"] } } },
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"properties": {
|
|
"semantic_tool": {
|
|
"allOf": [
|
|
{ "$ref": "https://paperclip.dev/schemas/prp/v1/semantic-tool.schema.json" },
|
|
{ "type": "object", "properties": { "phase": { "const": "input" } } }
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"if": { "properties": { "eventType": { "enum": ["semantic_tool.result", "mcp_app.tool_result"] } } },
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"properties": {
|
|
"semantic_tool": {
|
|
"allOf": [
|
|
{ "$ref": "https://paperclip.dev/schemas/prp/v1/semantic-tool.schema.json" },
|
|
{ "type": "object", "properties": { "phase": { "const": "result" } } }
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"if": { "properties": { "eventType": { "const": "semantic_tool.reconciled" } } },
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"properties": {
|
|
"semantic_tool": {
|
|
"allOf": [
|
|
{ "$ref": "https://paperclip.dev/schemas/prp/v1/semantic-tool.schema.json" },
|
|
{ "type": "object", "properties": { "phase": { "const": "reconciled" } } }
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"if": { "properties": { "eventType": { "const": "run.terminal" } } },
|
|
"then": {
|
|
"properties": {
|
|
"payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/terminal.schema.json" }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"if": { "properties": { "eventType": { "const": "run.result.proposed" } } },
|
|
"then": {
|
|
"properties": {
|
|
"payload": { "$ref": "https://paperclip.dev/schemas/prp/v1/result.schema.json" }
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"additionalProperties": true
|
|
}
|