Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
756 changes: 756 additions & 0 deletions docs/AUTOMATION-ADAPTER.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"emitted_at":"2026-08-30T04:00:05Z","event_id":"aev_01J0000000000000000000AEV1","invocation_id":"aiv_01J0000000000000000000AV01","kind":"adoption_confirmed","payload":{"execution_ref":"grf_01J00000000000000000000000"},"payload_digest":"sha256:40bc16fee112584d76602d0535035391fe93ef85c531aed75c3317ef3e7988b7","previous_payload_digest":"sha256:bb2991ec76f6c813988a05f2833545833bb96eb9ad5f95158d2b8eec2ec70401","producer_instance":"psyche-daemon-2c9d","schema_version":"psyche.automation_event.v1","sequence":1}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"invocation":{"action_class":"scheduled_dependency_upgrade","authority":{"approval_evidence":[{"approval_digest":"sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd","approval_ref":"threads-approval/val/0007/publication"}],"authority_profile_revision":"threads-profile-2026-08-01","threads_decision_digest":"sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","threads_decision_ref":"threads-decision/val/0007"},"automation":{"automation_id":"automation/payments-nightly","definition_digest":"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","definition_revision":"rev-41"},"brief":{"digest":"sha256:62b4f7a4b08aa68cac8b53fa7f380f3b9ea54b5eb5dc2d9a4a4c6c8fb56ae955","media_type":"application/json","size_bytes":466},"capabilities":{"granted":["workspace_write","network_fetch","publication_release"],"requested":["workspace_write","network_fetch","publication_release"],"scopes":{"credentials":["registry-token-ref"],"familiar":["payments-assistant"],"network":["crates.io","github.com"],"paths":["src/","Cargo.toml"],"principal":["val"],"project":["payments"],"publication":["release-candidate"],"repository":["github.com/opencoven/payments"],"runtime":["containerized"]}},"context":{"project_id":"project:payments","repository":{"commit":"3f9c2b1a7d5e4c8b0a9f2e6d1c3b5a7f9e0d2c4b","remote":"github.com/opencoven/payments"},"workspace_root":"/workspace/payments"},"correlation":{"causation_id":"sched-eval-2026-08-30T04:00:00Z","correlation_id":"corr-2026-08-30-000123"},"coven":{"attempt_id":"attempt-2026-08-30-000123-1","run_id":"run-2026-08-30-000123"},"deadline":{"cancellation_channel":"automation-cancel/payments-nightly","created_at":"2026-08-30T04:00:00Z","timeout_at":"2026-08-30T04:30:00Z"},"expectations":{"delivery_mode":"event_stream","result_schema":"psyche.automation_result.v1"},"familiar_binding":{"binding_digest":"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","binding_ref":"familiar-binding/val/rev-41"},"invocation_id":"aiv_01J0000000000000000000AV01","occurrence":{"fence_generation":7,"occurrence_id":"occ/payments-nightly/2026-08-30T04:00:00Z","occurrence_key":"occurrence/payments-nightly/2026-08-30T04:00:00Z"},"principal":{"principal_context_ref":"principal:val"},"privacy":{"privacy_class":"operational","retention_class":"standard"},"producer":{"contract_versions":{"coven":"automation.v1","familiar-contract":"familiar-embodiment-binding.v1","threads":"authority-profile-2026-08-01"},"producer_id":"coven","producer_instance":"coven-daemon-7f3a"},"risk_class":"protected","runtime":{"constraints":{"arch":["x86_64"],"os":["linux"]},"required_capabilities":["containerized","node24"]},"schema_version":"psyche.automation_invocation.v1"},"invocation_digest":"sha256:bb2991ec76f6c813988a05f2833545833bb96eb9ad5f95158d2b8eec2ec70401"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"result":{"artifacts":[{"artifact_id":"artifact-upgrade-report","digest":"sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee","expires_at":"2026-09-06T04:30:00Z","lane_id":"lane-upgrade","media_type":"text/plain","provenance":"lane-upgrade:test-output","size_bytes":34},{"artifact_id":"artifact-changelog","digest":"sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","expires_at":"2026-09-06T04:30:00Z","lane_id":"lane-release-gate","media_type":"text/markdown","provenance":"lane-release-gate:changelog","size_bytes":512}],"authentication":{"producer_id":"psyche","producer_instance":"psyche-daemon-2c9d","scheme":"sha256-digest-v1"},"bindings_exercised":{"authority":{"approval_events":[{"approval_digest":"sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd","approval_ref":"threads-approval/val/0007/publication","disposition":"rechecked"}],"threads_decision_digest":"sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"},"familiar_binding_digest":"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","runtime_capabilities":["containerized","node24"]},"cancellation_history":[],"capability_narrowing":[{"lane_id":"lane-upgrade","narrowed_scopes":{"publication":[]},"reason_code":"lane_class_code_change"}],"correlation":{"attempt_id":"attempt-2026-08-30-000123-1","occurrence_id":"occ/payments-nightly/2026-08-30T04:00:00Z","run_id":"run-2026-08-30-000123"},"external_effects":[{"disclosure_digest":"sha256:3333333333333333333333333333333333333333333333333333333333333333","effect_class":"publication","lane_id":"lane-release-gate","occurred_at":"2026-08-30T04:21:11Z","state":"confirmed"}],"invocation_digest":"sha256:bb2991ec76f6c813988a05f2833545833bb96eb9ad5f95158d2b8eec2ec70401","invocation_id":"aiv_01J0000000000000000000AV01","orchestration":{"execution_ref":"grf_01J00000000000000000000000","lanes":[{"lane_id":"lane-upgrade","lease_ref":"lease-upgrade-1","node_ref":"nod_01J00000000000000000000000","terminal_state":"completed","worker_session_ref":"session-upgrade-1"},{"lane_id":"lane-release-gate","lease_ref":"lease-gate-1","node_ref":"nod_01J00000000000000000000001","terminal_state":"completed","worker_session_ref":"session-gate-1"}]},"privacy":{"privacy_class":"operational","redacted":false,"retention_class":"standard"},"reason_code":"all_lanes_verified","recovery_history":[],"result_id":"ars_01J0000000000000000000ARS1","schema_version":"psyche.automation_result.v1","status":"completed","timing":{"final_event_cursor":12,"finished_at":"2026-08-30T04:21:14Z","started_at":"2026-08-30T04:00:06Z"},"verification":[{"evidence_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","lane_id":"lane-upgrade","method":"unit_tests","outcome":"verified"},{"evidence_digest":"sha256:2222222222222222222222222222222222222222222222222222222222222222","lane_id":"lane-release-gate","method":"release_gate","outcome":"verified"}]},"result_digest":"sha256:8abdb845d13916a655a6f4c5dd894ebcb324abfaf9e1cd3ab176bc43d243d472"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"lanes":[{"action_class":"code_change","depends_on":[],"lane_id":"lane-upgrade","protected":false,"summary":"Apply the dependency upgrade and run the unit tests"},{"action_class":"publication","depends_on":["lane-upgrade"],"lane_id":"lane-release-gate","protected":true,"summary":"Publish the release candidate and update the changelog"}],"objective":"Upgrade the payments dependency and verify the release gate","schema_version":"opencoven.orchestration_brief.v1"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/OpenCoven/psyche/main/docs/schemas/automation-adapter/psyche.automation_error.v1.schema.json",
"title": "psyche.automation_error.v1",
"description": "Structured, persistable refusal or failure document for the automation adapter boundary. It is the automation-boundary projection of the payload-free PortError vocabulary in crates/psyche-coven/src/error.rs: the port enum stays the in-process contract, while this document is what crosses a transport and may be durably retained as refusal evidence. Unlike psyche.error.v1 (crates/psyche-core/src/contracts/error.rs), which exhaustively decodes the daemon-facing ErrorCode::ALL vocabulary and is deliberately not persistable, this contract is persistable by design: a refused invocation must leave durable evidence of what was refused and why, without persisting any rejected payload bytes.",
"type": "object",
"additionalProperties": false,
"required": ["schema_version", "code", "refusal_class", "occurred_at", "detail"],
"properties": {
"schema_version": {
"const": "psyche.automation_error.v1",
"description": "Exact registry spelling; denied, never coerced."
},
"code": {
"enum": [
"invocation_invalid",
"invocation_unknown",
"invocation_conflict",
"invocation_stale",
"version_unsupported",
"binding_mismatch",
"principal_mismatch",
"authority_missing",
"authority_expired",
"capability_unavailable",
"runtime_unsatisfiable",
"deadline_exceeded",
"orchestration_store_unavailable",
"cancellation_unknown",
"reconciliation_unresolved"
],
"description": "Frozen automation refusal/failure vocabulary. At implementation time each value is mirrored into the canonical ErrorCode::ALL registry so the daemon surface can represent it without a second vocabulary (design decision D4 in docs/AUTOMATION-ADAPTER.md)."
},
"refusal_class": {
"enum": ["permanent", "retryable_after_reconciliation", "transport"],
"description": "`permanent` refusals are terminal for the invocation identity; `retryable_after_reconciliation` requires lookup/reconcile by the existing invocation_id, never a new key; `transport` failures carry no statement about durable state."
},
"occurred_at": {
"type": "string",
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?Z$"
},
"detail": {
"type": "object",
"additionalProperties": false,
"required": ["summary"],
"description": "Bounded, payload-free detail. Rejected input bytes are never embedded; at most a stable field name or category is retained, matching the payload-light rejection style of RejectionReason in crates/psyche-core/src/contracts/mod.rs.",
"properties": {
"summary": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"field": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"invocation_id": {
"type": "string",
"pattern": "^aiv_[0-9A-HJKMNP-TV-Z]{26}$",
"description": "Echoed when the invocation identity was parseable, so lookup/reconcile stays possible."
},
"conflict_digest": {
"type": "string",
"pattern": "^sha256:[0-9a-f]{64}$",
"description": "For invocation_conflict: the digest already adopted under this invocation_id, so the conflicting sender can self-identify the divergence."
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/OpenCoven/psyche/main/docs/schemas/automation-adapter/psyche.automation_event.v1.schema.json",
"title": "psyche.automation_event.v1",
"description": "One Psyche orchestration event for one adopted automation invocation. Events have the stable identity (invocation_id, sequence); sequences are strictly increasing per invocation with no gaps, matching the ordered-cursor rules of EventPage::validate_for in crates/psyche-coven/src/port.rs. Every event chains to its predecessor: the first event's previous_payload_digest is the adopted invocation_digest, and every later event's previous_payload_digest is the payload_digest of the event at sequence-1. Duplicate, out-of-order, or chain-breaking delivery can therefore never be mistaken for new state, and Coven persists its own cursor so replay never depends on a live connection.",
"type": "object",
"additionalProperties": false,
"required": [
"schema_version",
"event_id",
"invocation_id",
"sequence",
"emitted_at",
"producer_instance",
"kind",
"payload_digest",
"previous_payload_digest",
"payload"
],
"properties": {
"schema_version": {
"const": "psyche.automation_event.v1",
"description": "Exact registry spelling; denied, never coerced."
},
"event_id": {
"type": "string",
"pattern": "^aev_[0-9A-HJKMNP-TV-Z]{26}$",
"description": "Durable event identity, unique across all invocations."
},
"invocation_id": {
"type": "string",
"pattern": "^aiv_[0-9A-HJKMNP-TV-Z]{26}$",
"description": "The adopted invocation this event belongs to."
},
"sequence": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Strictly increasing per invocation, safe-integer bounded."
},
"emitted_at": {
"type": "string",
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?Z$",
"description": "RFC 3339 UTC instant at which Psyche durably recorded the event."
},
"producer_instance": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "Stable identity of the Psyche instance that recorded the event. A new instance after restart keeps the adopted history and continues the sequence; it never resets it."
},
"kind": {
"enum": [
"adoption_confirmed",
"orchestration_started",
"lane_planned",
"lane_state_changed",
"worker_session_bound",
"worker_session_unbound",
"approval_required",
"approval_granted",
"approval_denied",
"artifact_produced",
"artifact_verification_completed",
"capability_narrowed",
"execution_completed",
"execution_failed",
"cancellation_requested",
"cancellation_acknowledged",
"recovery_required",
"ambiguous_effect_disclosed",
"snapshot_reset"
],
"description": "Frozen event vocabulary. Unknown kinds are a decode failure and become quarantinable documents (crates/psyche-core/src/contracts/mod.rs inspect_typed_enums)."
},
"payload_digest": {
"type": "string",
"pattern": "^sha256:[0-9a-f]{64}$",
"description": "SHA-256 over the canonical JSON bytes of the payload object."
},
"previous_payload_digest": {
"type": "string",
"pattern": "^sha256:[0-9a-f]{64}$",
"description": "Chain link: payload_digest of the event at sequence-1, or the adopted invocation_digest for sequence 1."
},
"payload": {
"type": "object",
"maxProperties": 64,
"description": "Bounded, minimized event detail, already redacted to the principal authorization Psyche holds. Payloads are advisory observations; only the terminal psyche.automation_result.v1 is authoritative evidence.",
"additionalProperties": true
}
}
}
Loading