mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-09 06:15:21 +02:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Semantic tools cross a trust boundary between a provider and the control plane > - Durable runs need exact input, result, denial, duplicate, and reconciliation receipts > - Replay must reject unsupported required versions and mismatched receipt pairs > - This pull request adds the receipt builders and deterministic replay fixtures > - It keeps newer sequence and gap safety limits from the current stack > - The benefit is auditable semantic activity before more providers use it ## Linked Issues or Issue Description **Subsystem affected** packages/paperclip-runner **Problem or motivation** Semantic tool calls have basic authorization records, but durable replay does not yet cover reconciled calls, denial redaction, duplicate receipts, governance targets, or artifact references. **Proposed solution** Add bounded semantic receipt builders, a reconciled phase, strict pair binding, fail-closed version checks, and generated replay oracles for the important lifecycle cases. **Alternatives considered** The runner could store provider-native tool payloads. That would weaken protocol portability and make redaction and retry behavior provider-specific. **Roadmap alignment** This supports the existing experimental Paperclip Runner rollout. It does not enable a production adapter. ## What Changed - Add semantic input and result receipt builders. - Add optional reconciliation receipts for pending calls. - Reject unsupported semantic receipt versions. - Validate receipt correlation, operation, idempotency, and digest bindings. - Add deterministic replay fixtures and generated golden outputs. ## Verification - `pnpm --filter @paperclipai/paperclip-runner test:typescript` - `pnpm --filter @paperclipai/paperclip-runner typecheck:typescript` - `pnpm -r typecheck` - `pnpm build` - Replay golden and protocol manifest checks pass. - The branch changes 27 files relative to its declared base. ## Risks The main risk is accepting a receipt that belongs to another call or replaying a duplicate as a new mutation. Binding checks compare correlation, operation, idempotency, and content digest fields. Fixtures cover denials, duplicates, governance chains, optional fields, artifacts, and unsupported versions. > 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, `gpt-5`, with 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 either linked an existing public issue 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 - [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
168 lines
4.6 KiB
JSON
168 lines
4.6 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://paperclip.dev/schemas/prp/v1/semantic-tool.schema.json",
|
|
"title": "PRP provider-neutral semantic tool envelope",
|
|
"type": "object",
|
|
"required": [
|
|
"schema",
|
|
"schemaVersion",
|
|
"phase",
|
|
"operationId",
|
|
"callId",
|
|
"correlation",
|
|
"idempotencyKey",
|
|
"content"
|
|
],
|
|
"properties": {
|
|
"schema": { "const": "paperclip.prp.semantic_tool.v1" },
|
|
"schemaVersion": { "const": 1 },
|
|
"phase": { "enum": ["input", "result", "reconciled"] },
|
|
"operationId": { "$ref": "#/$defs/stableId" },
|
|
"callId": { "$ref": "#/$defs/stableId" },
|
|
"correlation": {
|
|
"type": "object",
|
|
"required": ["runId", "normalizedSessionId", "turnId", "itemId"],
|
|
"properties": {
|
|
"runId": { "$ref": "#/$defs/stableId" },
|
|
"normalizedSessionId": { "$ref": "#/$defs/stableId" },
|
|
"turnId": { "$ref": "#/$defs/stableId" },
|
|
"itemId": { "$ref": "#/$defs/stableId" },
|
|
"requestId": { "$ref": "#/$defs/stableId" }
|
|
},
|
|
"additionalProperties": true
|
|
},
|
|
"idempotencyKey": {
|
|
"type": ["string", "null"],
|
|
"minLength": 1,
|
|
"maxLength": 240
|
|
},
|
|
"content": { "$ref": "#/$defs/safeContent" },
|
|
"outcome": {
|
|
"enum": ["succeeded", "denied", "conflict", "duplicate", "unavailable", "failed"]
|
|
},
|
|
"code": { "$ref": "#/$defs/stableCode" },
|
|
"retryable": { "type": "boolean" },
|
|
"authorizationBoundary": {
|
|
"enum": ["company", "actor", "active_task", "grant", "governed_action", "lock", "revision"]
|
|
},
|
|
"operationReceiptId": { "$ref": "#/$defs/stableId" },
|
|
"auditReceiptId": { "$ref": "#/$defs/stableId" },
|
|
"currentRevision": {
|
|
"oneOf": [
|
|
{ "type": "integer", "minimum": 0 },
|
|
{ "$ref": "#/$defs/stableId" }
|
|
]
|
|
},
|
|
"duplicateOfReceiptId": { "$ref": "#/$defs/stableId" },
|
|
"artifactRefs": {
|
|
"type": "array",
|
|
"items": {
|
|
"allOf": [
|
|
{ "$ref": "#/$defs/safeReference" },
|
|
{
|
|
"type": "object",
|
|
"properties": { "kind": { "enum": ["artifact", "work_product"] } }
|
|
}
|
|
]
|
|
},
|
|
"uniqueItems": true
|
|
},
|
|
"targets": {
|
|
"type": "array",
|
|
"items": { "$ref": "#/$defs/immutableTarget" },
|
|
"uniqueItems": true
|
|
},
|
|
"causalRefs": {
|
|
"type": "array",
|
|
"items": { "$ref": "#/$defs/safeReference" },
|
|
"uniqueItems": true
|
|
}
|
|
},
|
|
"allOf": [
|
|
{
|
|
"if": {
|
|
"properties": { "phase": { "enum": ["result", "reconciled"] } },
|
|
"required": ["phase"]
|
|
},
|
|
"then": {
|
|
"required": [
|
|
"outcome",
|
|
"code",
|
|
"retryable",
|
|
"authorizationBoundary",
|
|
"operationReceiptId"
|
|
]
|
|
}
|
|
}
|
|
],
|
|
"additionalProperties": true,
|
|
"$defs": {
|
|
"stableId": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 240,
|
|
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]*$"
|
|
},
|
|
"stableCode": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"maxLength": 160,
|
|
"pattern": "^[a-z][a-z0-9_.:-]*$"
|
|
},
|
|
"safeContent": {
|
|
"type": "object",
|
|
"required": ["digest", "redactionDisposition", "references"],
|
|
"properties": {
|
|
"digest": {
|
|
"type": "string",
|
|
"pattern": "^sha256:[a-f0-9]{64}$"
|
|
},
|
|
"redactionDisposition": {
|
|
"enum": ["digest_only", "allowlisted_references", "redacted"]
|
|
},
|
|
"references": {
|
|
"type": "array",
|
|
"items": { "$ref": "#/$defs/safeReference" },
|
|
"uniqueItems": true
|
|
}
|
|
},
|
|
"additionalProperties": true
|
|
},
|
|
"safeReference": {
|
|
"type": "object",
|
|
"required": ["kind", "id"],
|
|
"properties": {
|
|
"kind": {
|
|
"enum": [
|
|
"task",
|
|
"document_revision",
|
|
"interaction",
|
|
"approval",
|
|
"decision",
|
|
"artifact",
|
|
"work_product",
|
|
"wake",
|
|
"monitor",
|
|
"audit",
|
|
"operation"
|
|
]
|
|
},
|
|
"id": { "$ref": "#/$defs/stableId" }
|
|
},
|
|
"additionalProperties": true
|
|
},
|
|
"immutableTarget": {
|
|
"type": "object",
|
|
"required": ["kind", "id", "immutable"],
|
|
"properties": {
|
|
"kind": { "enum": ["document_revision", "interaction", "approval", "decision"] },
|
|
"id": { "$ref": "#/$defs/stableId" },
|
|
"immutable": { "const": true },
|
|
"revisionId": { "$ref": "#/$defs/stableId" },
|
|
"decisionId": { "$ref": "#/$defs/stableId" }
|
|
},
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|