Files
PaperClipAI/packages/paperclip-runner/protocol/schemas/result.schema.json
Dotta b1cd261212 feat(runner): normalize provider event contracts (#12350)
## Thinking Path

> - The runner already persists PRP events, but provider-native activity
needs one bounded, provider-neutral vocabulary before additional
providers can be added safely.
> - The protocol catalog must describe capabilities without enabling or
authorizing a provider.
> - Provider normalization must not require an ACPX runtime dependency
merely to compile the shared event layer.
> - This pull request adds the event contract and pure normalizers only;
provider transports and production selection remain unchanged.

## Linked Issues or Issue Description

This is the first follow-up stacked on #12321. Codex, OpenCode, and ACP
runtimes expose different activity shapes. Without canonical
normalization, downstream task threads and traces would need
provider-specific branching and could retain unbounded or unsafe
payloads.

## What Changed

- Expand the PRP provider descriptor and canonical activity event
families.
- Add bounded Codex, OpenCode, and ACP event normalizers for plans,
tools, research, delegation, artifacts, review, safety, waits, and
notices.
- Preserve strict schema validation and regenerate the checked-in schema
bundle and manifest.
- Use a structural ACP event input so the provider-neutral layer does
not introduce or authorize an ACPX runtime dependency.
- Export the provider-event contract from the existing package root.

## Verification

- `pnpm --filter @paperclipai/paperclip-runner typecheck:typescript`
- `pnpm --filter @paperclipai/paperclip-runner test:typescript` — 11
files and 88 tests passed.
- `pnpm -r typecheck`
- `pnpm build`
- `git diff --check`
- The local full repository runner reached unrelated macOS
workspace-path fixture failures; the affected runner suites pass and the
repository CI shards are the handoff authority.
- Diff against the declared base: 8 files.

## Compatibility Boundary

- No provider transport, adapter, server route, feature flag, or runtime
selection changes.
- Catalog presence does not authorize discovery or execution.
- Existing Codex execution continues through its current path.
- No dependency, migration, workflow, or lockfile change.

## Risks

The main risk is accepting malformed or unbounded provider payloads.
Schema validation remains fail-closed, text/output fields are bounded
and redacted, unsafe paths and URLs are discarded, and representative
variants for every declared event family are covered by tests.

## Model Used

OpenAI Codex, GPT-5 family. The client does not expose the exact
deployment ID or context window. Agentic reasoning, tool use, and code
execution were 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 described the issue in-PR following the relevant template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal task
identifier
- [x] I have run the affected local tests and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated the compatibility notes for this change
- [x] I have considered and documented risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open actionable comments
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-08-29 19:44:24 -05:00

160 lines
5.6 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://paperclip.dev/schemas/prp/v1/result.schema.json",
"title": "PRP structured run result",
"type": "object",
"required": [
"schema",
"reportedWorkDisposition",
"summary",
"completionClaim",
"evidence",
"verification",
"attentionRequests",
"artifacts"
],
"properties": {
"schema": { "const": "paperclip.run_result.v1" },
"reportedWorkDisposition": {
"enum": ["done", "blocked", "needs_review", "yielded"]
},
"summary": { "type": "string", "minLength": 1, "maxLength": 12000 },
"completionClaim": {
"type": "object",
"required": ["contractRevision", "objectiveSatisfied", "criteria", "remainingWork"],
"properties": {
"contractRevision": { "type": "string", "minLength": 1 },
"objectiveSatisfied": { "type": "boolean" },
"criteria": {
"type": "array",
"items": {
"type": "object",
"required": ["criterionId", "status", "evidenceRefs"],
"properties": {
"criterionId": { "type": "string", "minLength": 1 },
"status": { "enum": ["satisfied", "not_satisfied", "unknown"] },
"evidenceRefs": { "type": "array", "items": { "type": "string" } },
"explanation": { "type": "string" }
},
"additionalProperties": true
}
},
"remainingWork": {
"type": "array",
"items": {
"type": "object",
"required": ["description", "blocksCompletion"],
"properties": {
"description": { "type": "string", "minLength": 1 },
"blocksCompletion": { "type": "boolean" }
},
"additionalProperties": true
}
}
},
"additionalProperties": true
},
"evidence": { "type": "array", "items": { "type": "object" } },
"verification": {
"type": "array",
"description": "Checks used to verify the work. Use failed only when the check actually ran and found a defect in the work. If a check could not run or complete because the environment, tool, dependency, permission, credential, policy, external service, or budget was unavailable, use not_run with reasonCode even when the attempted command exited non-zero.",
"items": {
"type": "object",
"required": ["commandOrCheck", "status"],
"properties": {
"commandOrCheck": { "type": "string", "minLength": 1 },
"status": {
"enum": ["passed", "failed", "not_run"],
"description": "passed means the check ran and succeeded; failed means it ran to a meaningful verdict and found the work incorrect; not_run means no meaningful verdict was possible because the check was not attempted or could not complete."
},
"reasonCode": {
"description": "Required for not_run; identify why the check had no meaningful verdict.",
"enum": [
"environment_unavailable",
"tool_unavailable",
"dependency_missing",
"permission_denied",
"credential_missing",
"policy_restricted",
"external_service_unavailable",
"budget_exhausted",
"other"
]
},
"detail": { "type": "string" },
"artifactRef": { "type": "string" }
},
"additionalProperties": true
}
},
"blocker": {
"type": "object",
"required": ["reasonCode", "owner", "unblockAction", "scope"],
"properties": {
"reasonCode": { "type": "string", "minLength": 1 },
"owner": {
"type": "object",
"required": ["kind", "name"],
"properties": {
"kind": { "enum": ["agent", "user", "system", "external"] },
"name": { "type": "string", "minLength": 1 }
},
"additionalProperties": true
},
"unblockAction": { "type": "string", "minLength": 1 },
"scope": { "enum": ["current_track", "task_wide"] }
},
"additionalProperties": true
},
"attentionRequests": {
"type": "array",
"items": {
"type": "object",
"properties": {
"kind": { "type": "string", "minLength": 1 },
"summary": { "type": "string", "minLength": 1 },
"ownerClass": { "enum": ["human", "agent", "external_system"] },
"targetAgentId": { "type": "string", "minLength": 1 }
},
"additionalProperties": true
}
},
"artifacts": {
"type": "array",
"items": {
"type": "object",
"required": ["kind", "ref"],
"properties": {
"kind": { "type": "string", "minLength": 1 },
"ref": { "type": "string", "minLength": 1 },
"title": { "type": "string" }
},
"additionalProperties": true
}
},
"continuation": {
"type": "object",
"required": ["kind", "summary", "idempotencyKey"],
"properties": {
"kind": {
"enum": ["same_agent", "retry", "delegated_issue", "response_wake", "monitor"]
},
"summary": { "type": "string", "minLength": 1 },
"idempotencyKey": { "type": "string", "minLength": 1 }
},
"additionalProperties": true
}
},
"allOf": [
{
"if": { "properties": { "reportedWorkDisposition": { "const": "blocked" } } },
"then": { "required": ["blocker"] }
},
{
"if": { "properties": { "reportedWorkDisposition": { "const": "yielded" } } },
"then": { "required": ["continuation"] }
}
],
"additionalProperties": true
}