mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-12 22:56:58 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Native runs execute through the Paperclip Runner, which turns provider output (Codex, OpenCode, Claude through ACPX) into durable runner events > - In the restart chaos campaign, events from an earlier turn or runner generation failed the current turn about ten times (RC-15, 20, 20b, 20c, 33, 33b, 59 and 61) > - #19718, #19722, #19772 and #19783 each special-cased one variant, and other variants still fail the run > - The durable-ownership plan (section G, invariant 6) asks for one rule: every event carries its generation and turn, and an earlier generation's events are recorded as history and never fail the current turn > - This pull request stamps the runner generation on every event and applies one stale-event rule in the ACPX provider state, the Codex driver (which Runnerd also uses for OpenCode) and the pending `turn.start` check > - The benefit is that a late report about a settled or restored turn no longer stops a healthy turn, while events for a turn the runner never saw still fail closed ## Linked Issues or Issue Description Refs #19718, #19722, #19772, #19783 **What happened?** A runner or provider can report a turn after that turn settled: a resumed provider reports the lost turn's usage or terminal, an ACPX sidecar emits a last delta after the turn terminal, or a held failure of the previous turn sits in front of a new `turn.start`. Several of these paths fail the current turn: ACPX `AcpxEventScope` rejects any event for a non-active turn ("named a stale turn"), the Codex driver fails `turn_binding_mismatch` for a settled turn's late item between turns, and `runnerdPendingTurnStartFailure` reports any held non-recoverable failure, whatever turn it names. Runner events carried no generation. **Expected behavior** An event for a turn that is not active, and that an earlier generation accepted or this generation already settled, is recorded as history and never fails the current turn. An event for a turn the runner never saw still fails closed. **Steps to reproduce** ACPX: settle turn 1, start turn 2, and deliver a late `runtime.event` for turn 1. Before this change, the provider state returns an error and the run fails. ## What Changed - Runner (`durable/state.rs`, `durable/runner.rs`): every event payload carries `generation`, the runner process generation that emitted it. A runner process that recovers state starts the next generation (`begin_recovered_generation`); it is saved with the next normal write, so recovery adds no write before the first turn. Loading stays pure. Old saved state loads as generation 0. Outbox events keep their original generation. - PRP event schemas v1–v3 declare the optional `generation` property; generated validators and the manifest are regenerated. - ACPX (`acpx_event_scope.rs`, `acpx_provider_state.rs`): an event that names a settled turn of this run becomes a bounded `stale_generation_event` diagnostic (32 per state) and changes no state. Unknown turns still fail. - Codex driver (`codex-session-state.ts`, `codex-session-notifications.ts`): one predicate, `isHistoryTurn()`: the turn is not active, and it was restored from the checkpoint (an earlier generation) or settled in this generation. The classifier's stale-turn branch, the resume-usage branch, restored-terminal replay and the main fail point (`notificationNamesActiveTurn`) all use it. A terminal for an earlier generation's turn is history even when it disagrees with the checkpoint. A terminal that contradicts a turn this same generation settled is still a `conflicting_turn_terminal` integrity failure, and a provider that starts a settled turn again is still rejected. - Transport (`runnerd-codex-transport.ts`): a pending `turn.start` ignores a held failure that names another provider turn. - `DURABLE_TRANSPORT.md` documents the stamp and the rule. ## Verification - `cargo test -p paperclip-runner-core`: new `records_late_events_for_a_settled_turn_as_history` (red before), `stamps_every_event_with_the_runner_process_generation`; two existing ACPX tests now assert "recorded as history, no state change" instead of "rejected". Durable tests: 112 passed. `cargo fmt` clean. - `codex-app-server-driver.stale-generation.test.ts` (new, 9 tests): late item, delta, terminal and workspace change for a settled turn during and before the next turn, an earlier generation's conflicting terminal after recovery, and an unknown turn that still fails. Red on master: 8 of 9 (the during-turn cases on master already dropped the event, with a different diagnostic; the between-turn and recovery cases failed the session). - `runnerd-pending-turn-start-failure.test.ts` (new): an earlier turn's held failure no longer fails the pending start; the pending turn's own failure and a failed run terminal still do. - `vitest run src/drivers/codex src/live/runnerd-codex-transport`: 787 passed; 2 Codex executable-resolution tests timed out under host load and pass when run alone. - `tsc -p tsconfig.json` for the runner package, `check:protocol-types`, `check:replay-goldens`: clean. - Not run: chaos waves (the coordinator schedules them on this host). ## Risks - A late report about a settled turn is now dropped with a diagnostic instead of failing. A provider that keeps working on a settled turn could have its output ignored silently; a provider that starts a settled turn again, or names a turn the runner never saw, still fails closed. - `generation` is a new optional field. Consumers that do not know it ignore it, as the PRP contract requires. - The generation counter is written with the next normal state save, so there is no new write before `turn.start`. > 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 - Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, via Claude Code with tool use (shell, file edits, test execution). Extended reasoning enabled. ## 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 either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
745 lines
21 KiB
JSON
745 lines
21 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://paperclip.dev/schemas/prp/v3/event.schema.json",
|
|
"title": "PRP v3 native event",
|
|
"type": "object",
|
|
"required": [
|
|
"schema",
|
|
"sourceEventId",
|
|
"sourceSeq",
|
|
"sourceInstanceId",
|
|
"sourceKind",
|
|
"runId",
|
|
"eventType",
|
|
"schemaVersion",
|
|
"priority",
|
|
"emittedAt",
|
|
"payload"
|
|
],
|
|
"properties": {
|
|
"schema": {
|
|
"const": "paperclip.prp.event.v3"
|
|
},
|
|
"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"
|
|
]
|
|
},
|
|
"generation": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"maximum": 9007199254740991,
|
|
"description": "The runner process generation that emitted the event. A consumer records an event from an earlier generation for a turn that is not active as history; it never fails the current turn."
|
|
},
|
|
"runId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160
|
|
},
|
|
"normalizedSessionId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160
|
|
},
|
|
"itemId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160
|
|
},
|
|
"eventType": {
|
|
"enum": [
|
|
"runner.connected",
|
|
"runner.reconnected",
|
|
"runner.reconciled",
|
|
"runner.disconnected",
|
|
"runner.draining",
|
|
"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",
|
|
"plan.proposed",
|
|
"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",
|
|
"session.capabilities.updated",
|
|
"session.goal.snapshot",
|
|
"session.goal.updated",
|
|
"session.goal.cleared",
|
|
"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",
|
|
"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",
|
|
"external_provider.dispatch_requested",
|
|
"external_provider.operation_settled",
|
|
"external_provider.input_available",
|
|
"auth.credentials.updated",
|
|
"runtime.activity.recorded"
|
|
]
|
|
},
|
|
"schemaVersion": {
|
|
"const": 3
|
|
},
|
|
"priority": {
|
|
"enum": [
|
|
0,
|
|
1,
|
|
2
|
|
]
|
|
},
|
|
"emittedAt": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"observedAt": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"payload": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
},
|
|
"debug": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"allOf": [
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"enum": [
|
|
"session.goal.snapshot",
|
|
"session.goal.updated"
|
|
]
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"required": [
|
|
"goal"
|
|
],
|
|
"properties": {
|
|
"goal": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "https://paperclip.dev/schemas/prp/v2/session-goal.schema.json#/$defs/snapshot"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"type": "object"
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "session.capabilities.updated"
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"required": [
|
|
"sessionGoals"
|
|
],
|
|
"properties": {
|
|
"sessionGoals": {
|
|
"$ref": "https://paperclip.dev/schemas/prp/v2/session-goal.schema.json#/$defs/capability"
|
|
},
|
|
"turnControls": {
|
|
"$ref": "https://paperclip.dev/schemas/prp/v1/provider-descriptor.schema.json#/$defs/turnControls"
|
|
}
|
|
},
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"type": "object"
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "external_provider.dispatch_requested"
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"oneOf": [
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"binding": {
|
|
"type": "object",
|
|
"properties": {
|
|
"companyId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"agentId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"runId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"normalizedSessionId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingGeneration": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"assignmentRevision": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"companyId",
|
|
"agentId",
|
|
"bindingId",
|
|
"runId",
|
|
"normalizedSessionId",
|
|
"turnId",
|
|
"bindingGeneration",
|
|
"assignmentRevision"
|
|
]
|
|
},
|
|
"text": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 1048576
|
|
},
|
|
"instructions": {
|
|
"type": "string",
|
|
"maxLength": 1048576
|
|
},
|
|
"acceptByUnixMs": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"expiresAtUnixMs": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"completionContract": {
|
|
"type": "object",
|
|
"properties": {
|
|
"revision": {
|
|
"type": "string",
|
|
"minLength": 1
|
|
},
|
|
"criterionIds": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"maxItems": 256,
|
|
"uniqueItems": true,
|
|
"items": {
|
|
"type": "string",
|
|
"minLength": 1
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"revision",
|
|
"criterionIds"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"tools": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object"
|
|
},
|
|
"maxItems": 512
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"binding",
|
|
"text",
|
|
"instructions",
|
|
"acceptByUnixMs",
|
|
"expiresAtUnixMs",
|
|
"completionContract",
|
|
"tools"
|
|
]
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"binding": {
|
|
"type": "object",
|
|
"properties": {
|
|
"companyId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"agentId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"runId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"normalizedSessionId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingGeneration": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"assignmentRevision": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"companyId",
|
|
"agentId",
|
|
"bindingId",
|
|
"runId",
|
|
"normalizedSessionId",
|
|
"turnId",
|
|
"bindingGeneration",
|
|
"assignmentRevision"
|
|
]
|
|
},
|
|
"kind": {
|
|
"const": "authority_revoked"
|
|
},
|
|
"reason": {
|
|
"type": "string"
|
|
},
|
|
"externalStopConfirmed": {
|
|
"const": false
|
|
}
|
|
},
|
|
"required": [
|
|
"binding",
|
|
"kind",
|
|
"externalStopConfirmed"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"type": "object"
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "external_provider.operation_settled"
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"properties": {
|
|
"binding": {
|
|
"type": "object",
|
|
"properties": {
|
|
"companyId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"agentId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"runId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"normalizedSessionId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingGeneration": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"assignmentRevision": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"companyId",
|
|
"agentId",
|
|
"bindingId",
|
|
"runId",
|
|
"normalizedSessionId",
|
|
"turnId",
|
|
"bindingGeneration",
|
|
"assignmentRevision"
|
|
]
|
|
},
|
|
"requestId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"outcome": {
|
|
"type": "object"
|
|
}
|
|
},
|
|
"required": [
|
|
"binding",
|
|
"requestId",
|
|
"outcome"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
},
|
|
"type": "object"
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "external_provider.input_available"
|
|
}
|
|
},
|
|
"type": "object"
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"payload": {
|
|
"type": "object",
|
|
"properties": {
|
|
"binding": {
|
|
"type": "object",
|
|
"properties": {
|
|
"companyId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"agentId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"runId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"normalizedSessionId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"bindingGeneration": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"assignmentRevision": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"companyId",
|
|
"agentId",
|
|
"bindingId",
|
|
"runId",
|
|
"normalizedSessionId",
|
|
"turnId",
|
|
"bindingGeneration",
|
|
"assignmentRevision"
|
|
]
|
|
},
|
|
"requestId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"turnId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"inputDigest": {
|
|
"type": "string",
|
|
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
},
|
|
"response": {
|
|
"$ref": "https://paperclip.dev/schemas/prp/v1/question-response.schema.json"
|
|
}
|
|
},
|
|
"required": [
|
|
"binding",
|
|
"requestId",
|
|
"turnId",
|
|
"inputDigest",
|
|
"response"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
},
|
|
"type": "object"
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "auth.credentials.updated"
|
|
}
|
|
}
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"sourceKind": {
|
|
"const": "runner"
|
|
},
|
|
"priority": {
|
|
"const": 0
|
|
},
|
|
"payload": {
|
|
"$ref": "https://paperclip.dev/schemas/prp/v1/auth-credentials.schema.json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"eventType": {
|
|
"const": "runtime.activity.recorded"
|
|
}
|
|
}
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"sourceKind": {
|
|
"const": "runner"
|
|
},
|
|
"priority": {
|
|
"const": 1
|
|
},
|
|
"payload": {
|
|
"type": "object",
|
|
"required": [
|
|
"namespace",
|
|
"activityKey"
|
|
],
|
|
"properties": {
|
|
"namespace": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160,
|
|
"pattern": "^[^\\u0000-\\u001f\\u007f]+$"
|
|
},
|
|
"activityKey": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160,
|
|
"pattern": "^[^\\u0000-\\u001f\\u007f]+$"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"additionalProperties": true
|
|
}
|