diff --git a/capabilities/core/core.record-nudge-event/1.1.0/contract.json b/capabilities/core/core.record-nudge-event/1.1.0/contract.json new file mode 100644 index 0000000..5a5ed1f --- /dev/null +++ b/capabilities/core/core.record-nudge-event/1.1.0/contract.json @@ -0,0 +1,303 @@ +{ + "kind": "capability_contract", + "schema_version": "1.0.0", + "id": "core.record-nudge-event", + "namespace": "core", + "name": "record-nudge-event", + "version": "1.1.0", + "lifecycle": "active", + "owner": { + "team": "loop", + "contact": "founders@loop.dev" + }, + "summary": "Constructs a pure audit/event payload for a nudge that was selected and messaged.", + "description": "Pure WF3 capability. Builds a deterministic nudge event record (event_id, ordinal, channel, intensity, preview) for downstream persistence.\n\nImplemented and smoke-tested matrix (use_cases):\n- soft intensity first nudge\n- escalate intensity with ordinal from prior count\n- direct intensity mid-sequence nudge\n- invalid_input when item_id is empty\n\nKnown limitations (intentional in 1.1.0):\n- reason_code invalid_intensity removed; intensity is a schema enum so host validation rejects unknown values before the guest runs\n- Event is constructed only; persistence is caller-owned", + "use_cases": [ + { + "scenario": "As a follow-up engine, I want an audit record after generating a soft nudge, so that later escalations can see prior outreach.", + "input_example": { + "item_id": "ai-1", + "owner_id": "user-ada", + "intensity": "soft", + "channel": "in_app", + "message_preview": "Reminder: Send the revised proposal", + "event_at": "2026-08-07T10:00:00Z", + "prior_nudge_count": 0 + }, + "output_example": { + "event": { + "event_id": "nudge-ai-1-1", + "item_id": "ai-1", + "owner_id": "user-ada", + "intensity": "soft", + "channel": "in_app", + "message_preview": "Reminder: Send the revised proposal", + "event_at": "2026-08-07T10:00:00Z", + "nudge_ordinal": 1 + }, + "reason_code": "ok", + "evaluation_trace": [ + "constructed nudge event", + "ordinal=1" + ] + }, + "happy": true, + "persona_ref": "runtime-engineer" + }, + { + "scenario": "As a system, I want escalate intensity recorded with a higher ordinal, so that nudge history reflects increasing pressure.", + "input_example": { + "item_id": "ai-9", + "owner_id": "user-bob", + "intensity": "escalate", + "channel": "manager", + "message_preview": "Escalation: overdue item", + "event_at": "2026-08-07T11:00:00Z", + "prior_nudge_count": 3 + }, + "output_example": { + "event": { + "event_id": "nudge-ai-9-4", + "item_id": "ai-9", + "owner_id": "user-bob", + "intensity": "escalate", + "channel": "manager", + "message_preview": "Escalation: overdue item", + "event_at": "2026-08-07T11:00:00Z", + "nudge_ordinal": 4 + }, + "reason_code": "ok", + "evaluation_trace": [ + "constructed nudge event", + "ordinal=4" + ] + }, + "happy": true, + "persona_ref": "collaboration-product-owner" + }, + { + "scenario": "As a WF3 workflow author, I want a direct-intensity nudge event with ordinal prior+1, so that mid-sequence nudges stay ordered.", + "input_example": { + "item_id": "ai-2", + "owner_id": "user-ada", + "intensity": "direct", + "channel": "in_app", + "message_preview": "Please complete", + "event_at": "2026-08-07T12:00:00Z", + "prior_nudge_count": 1 + }, + "output_example": { + "event": { + "event_id": "nudge-ai-2-2", + "item_id": "ai-2", + "owner_id": "user-ada", + "intensity": "direct", + "channel": "in_app", + "message_preview": "Please complete", + "event_at": "2026-08-07T12:00:00Z", + "nudge_ordinal": 2 + }, + "reason_code": "ok", + "evaluation_trace": [ + "constructed nudge event", + "ordinal=2" + ] + }, + "happy": true, + "persona_ref": "runtime-engineer" + }, + { + "scenario": "As a WF3 workflow author, I want invalid_input when item_id is empty, so that orphan nudge events cannot be recorded.", + "input_example": { + "item_id": "", + "owner_id": "user-ada", + "intensity": "soft", + "channel": "in_app", + "message_preview": "x", + "event_at": "2026-08-07T10:00:00Z", + "prior_nudge_count": 0 + }, + "output_example": { + "event": { + "event_id": "", + "item_id": "", + "intensity": "", + "event_at": "", + "nudge_ordinal": 0 + }, + "reason_code": "invalid_input", + "evaluation_trace": [] + }, + "happy": false, + "persona_ref": "runtime-engineer" + } + ], + "inputs": { + "schema": { + "type": "object", + "required": [ + "item_id", + "intensity", + "event_at", + "prior_nudge_count" + ], + "properties": { + "item_id": { + "type": "string" + }, + "owner_id": { + "type": "string" + }, + "intensity": { + "type": "string", + "enum": [ + "soft", + "direct", + "escalate" + ] + }, + "channel": { + "type": "string" + }, + "message_preview": { + "type": "string" + }, + "event_at": { + "type": "string" + }, + "prior_nudge_count": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "outputs": { + "schema": { + "type": "object", + "required": [ + "event", + "reason_code" + ], + "properties": { + "event": { + "type": "object", + "required": [ + "event_id", + "item_id", + "intensity", + "event_at", + "nudge_ordinal" + ], + "properties": { + "event_id": { + "type": "string" + }, + "item_id": { + "type": "string" + }, + "owner_id": { + "type": "string" + }, + "intensity": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "message_preview": { + "type": "string" + }, + "event_at": { + "type": "string" + }, + "nudge_ordinal": { + "type": "integer" + } + } + }, + "reason_code": { + "type": "string", + "enum": [ + "ok", + "invalid_input" + ] + }, + "evaluation_trace": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "preconditions": [], + "postconditions": [ + { + "id": "deterministic", + "description": "Identical inputs produce identical outputs" + } + ], + "side_effects": [ + { + "kind": "memory_only", + "description": "Pure event payload construction; no persistence I/O" + } + ], + "emits": [], + "consumes": [], + "permissions": [ + { + "id": "core.record-nudge-event" + } + ], + "execution": { + "binary_format": "wasm", + "entrypoint": { + "kind": "wasi-command", + "command": "run" + }, + "preferred_targets": [ + "local", + "edge", + "browser" + ], + "constraints": { + "host_api_access": "none", + "network_access": "forbidden", + "filesystem_access": "none" + } + }, + "policies": [], + "dependencies": [], + "provenance": { + "source": "ai-assisted", + "author": "loop-founders + traverse-capability-author", + "created_at": "2026-08-08T06:00:00Z", + "spec_ref": "core.record-nudge-event@1.1.0", + "adr_refs": [ + "persona-council-review-2026-08-08" + ], + "exception_refs": [] + }, + "evidence": [ + { + "evidence_id": "core-record-nudge-event-1.1.0-contract-validation", + "type": "contract_validation", + "status": "passed" + } + ], + "service_type": "stateless", + "permitted_targets": [ + "local", + "edge", + "browser", + "cloud" + ], + "artifact_type": "native", + "artifact": { + "digest": "sha256:adffdaf2b9160e5830762ed1ab158d1faecd35d87c96df7886848c54d09850ac", + "url": "https://github.com/traverse-framework/registry/releases/download/artifacts/core.record-nudge-event-1.1.0/core-record-nudge-event.wasm" + } +}