changedInput schema / properties / steps / items / anyOf
Previous value: -[
- {
- "oneOf": [
- {
- "properties": {
- "action": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
- },
- "assumptions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
- },
- "condition": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Always null on events; included for shape compatibility across variants."
- },
- "confidence": {
- "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "conflicts": {
- "items": {
- "properties": {
- "id": {
- "minLength": 1,
- "type": "string"
- },
- "mappedVersionIndex": {
- "description": "Zero-based index in versions of the account represented by this step in the current diagram. Omit when unknown. Update or clear it when the diagram or versions change. This records the diagram content, not a resolved conflict.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "question": {
- "minLength": 1,
- "type": "string"
- },
- "versions": {
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "title": {
- "description": "Short heading describing this account; the excerpt remains the exact source quote",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt",
- "captureId"
- ],
- "type": "object"
- },
- "minItems": 2,
- "type": "array"
- }
- },
- "required": [
- "id",
- "question",
- "versions"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "dataObjects": {
- "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
- "items": {
- "properties": {
- "access": {
- "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
- "enum": [
- "read",
- "write"
- ],
- "type": "string"
- },
- "name": {
- "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
- "minLength": 1,
- "type": "string"
- },
- "state": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
- }
- },
- "required": [
- "name",
- "state",
- "access"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "description": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Optional prose describing what happens at this event. May be null for structural markers."
- },
- "effort": {
- "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
- "items": {
- "properties": {
- "basis": {
- "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
- "enum": [
- "stated",
- "estimated",
- "unknown"
- ],
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
- "minLength": 1,
- "type": "string"
- },
- "frequency": {
- "anyOf": [
- {
- "properties": {
- "count": {
- "description": "How many times the work happens per period. Example: 40",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the count covers. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "count",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "How often the work happens for this person. Null unless they gave a count."
- },
- "person": {
- "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
- "minLength": 1,
- "type": "string"
- },
- "timeSpent": {
- "anyOf": [
- {
- "properties": {
- "hours": {
- "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the hours cover. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "hours",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
- }
- },
- "required": [
- "person",
- "timeSpent",
- "frequency",
- "basis",
- "excerpt"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "exceptions": {
- "description": "Distinct failure modes for this step in display order. Use an empty array when none are documented. Preserve each id when the same exception is edited or regenerated.",
- "items": {
- "properties": {
- "exception": {
- "description": "A distinct failure mode that can happen at this step.",
- "minLength": 1,
- "type": "string"
- },
- "frequency": {
- "anyOf": [
- {
- "enum": [
- "rare",
- "occasional",
- "frequent"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Observed frequency. Null unless evidence explicitly supports rare, occasional, or frequent."
- },
- "handling": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "How the team responds to this exception. Null when the response was not documented."
- },
- "id": {
- "description": "Stable identifier for this exception. Preserve it when the same exception is edited or regenerated. Example: \"exception-po-mismatch\"",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "id",
- "exception",
- "handling",
- "frequency"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "extraCaptureNeeded": {
- "anyOf": [
- {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ]
- },
- "extraCaptureNeeds": {
- "items": {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "id": {
- "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- },
- "input": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
- },
- "laneId": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
- },
- "linkedAgentId": {
- "anyOf": [
- {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
- },
- "nodeSubtype": {
- "description": "BPMN event subtype. \"start\" (entry trigger), \"end\" (terminal state), \"timer\" (time-based wait; title it with the duration, deadline, or cadence the captures give, e.g. \"Supplier reply: 2-3 days\"), \"message\" (external communication), \"escalation\" (route to higher authority).",
- "enum": [
- "start",
- "end",
- "timer",
- "message",
- "escalation"
- ],
- "type": "string"
- },
- "nodeType": {
- "const": "event",
- "type": "string"
- },
- "openQuestions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
- },
- "output": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
- },
- "pool": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
- },
- "rationale": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Optional reason for the event's existence. May be null for structural markers."
- },
- "readiness": {
- "anyOf": [
- {
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
- },
- "readinessRationale": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
- },
- "role": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
- },
- "sources": {
- "description": "Evidence supporting this event. Empty array allowed (structural markers carry no evidence); non-empty values must follow the source schema.",
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "system": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
- },
- "targetSteps": {
- "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
- "items": {
- "properties": {
- "isDefault": {
- "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
- "type": "boolean"
- },
- "label": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
- },
- "stepId": {
- "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "stepId",
- "label",
- "isDefault"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "title": {
- "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "id",
- "targetSteps",
- "title",
- "action",
- "role",
- "system",
- "input",
- "output",
- "exceptions",
- "assumptions",
- "openQuestions",
- "confidence",
- "nodeType",
- "nodeSubtype",
- "description",
- "rationale",
- "sources",
- "condition"
- ],
- "type": "object"
- },
- {
- "properties": {
- "action": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
- },
- "assumptions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
- },
- "condition": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Optional precondition that gates this task. Null when the task is unconditional. Example: \"Only when invoice total exceeds $10,000\""
- },
- "confidence": {
- "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "conflicts": {
- "items": {
- "properties": {
- "id": {
- "minLength": 1,
- "type": "string"
- },
- "mappedVersionIndex": {
- "description": "Zero-based index in versions of the account represented by this step in the current diagram. Omit when unknown. Update or clear it when the diagram or versions change. This records the diagram content, not a resolved conflict.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "question": {
- "minLength": 1,
- "type": "string"
- },
- "versions": {
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "title": {
- "description": "Short heading describing this account; the excerpt remains the exact source quote",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt",
- "captureId"
- ],
- "type": "object"
- },
- "minItems": 2,
- "type": "array"
- }
- },
- "required": [
- "id",
- "question",
- "versions"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "dataObjects": {
- "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
- "items": {
- "properties": {
- "access": {
- "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
- "enum": [
- "read",
- "write"
- ],
- "type": "string"
- },
- "name": {
- "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
- "minLength": 1,
- "type": "string"
- },
- "state": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
- }
- },
- "required": [
- "name",
- "state",
- "access"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "description": {
- "description": "Full prose paragraph describing what happens in this step in natural language. Used for documentation reconstruction. Example: \"Finance reviews the invoice in NetSuite, checking line item accuracy and matching against the purchase order before flagging for approval.\"",
- "minLength": 1,
- "type": "string"
- },
- "effort": {
- "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
- "items": {
- "properties": {
- "basis": {
- "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
- "enum": [
- "stated",
- "estimated",
- "unknown"
- ],
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
- "minLength": 1,
- "type": "string"
- },
- "frequency": {
- "anyOf": [
- {
- "properties": {
- "count": {
- "description": "How many times the work happens per period. Example: 40",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the count covers. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "count",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "How often the work happens for this person. Null unless they gave a count."
- },
- "person": {
- "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
- "minLength": 1,
- "type": "string"
- },
- "timeSpent": {
- "anyOf": [
- {
- "properties": {
- "hours": {
- "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the hours cover. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "hours",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
- }
- },
- "required": [
- "person",
- "timeSpent",
- "frequency",
- "basis",
- "excerpt"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "exceptions": {
- "description": "Distinct failure modes for this step in display order. Use an empty array when none are documented. Preserve each id when the same exception is edited or regenerated.",
- "items": {
- "properties": {
- "exception": {
- "description": "A distinct failure mode that can happen at this step.",
- "minLength": 1,
- "type": "string"
- },
- "frequency": {
- "anyOf": [
- {
- "enum": [
- "rare",
- "occasional",
- "frequent"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Observed frequency. Null unless evidence explicitly supports rare, occasional, or frequent."
- },
- "handling": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "How the team responds to this exception. Null when the response was not documented."
- },
- "id": {
- "description": "Stable identifier for this exception. Preserve it when the same exception is edited or regenerated. Example: \"exception-po-mismatch\"",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "id",
- "exception",
- "handling",
- "frequency"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "extraCaptureNeeded": {
- "anyOf": [
- {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ]
- },
- "extraCaptureNeeds": {
- "items": {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "id": {
- "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- },
- "input": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
- },
- "laneId": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
- },
- "linkedAgentId": {
- "anyOf": [
- {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
- },
- "nodeSubtype": {
- "description": "BPMN task subtype. \"user\" (human work), \"service\" (automated/API call), \"send\"/\"receive\" (messaging), \"manual\" (offline physical work), \"businessRule\" (rule engine), \"script\" (code execution).",
- "enum": [
- "user",
- "service",
- "send",
- "receive",
- "manual",
- "businessRule",
- "script"
- ],
- "type": "string"
- },
- "nodeType": {
- "const": "task",
- "type": "string"
- },
- "openQuestions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
- },
- "output": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
- },
- "pool": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
- },
- "rationale": {
- "description": "Why this step exists in the process — its purpose or business reason. Used by downstream agents to assess whether the step is essential or removable. Example: \"Catches mispriced line items before they reach the customer and prevents downstream credit notes.\"",
- "minLength": 1,
- "type": "string"
- },
- "readiness": {
- "anyOf": [
- {
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
- },
- "readinessRationale": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
- },
- "role": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
- },
- "sources": {
- "description": "Evidence supporting this step's existence and details. At least one source is required — every step must trace back to something in the captures.",
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt"
- ],
- "type": "object"
- },
- "minItems": 1,
- "type": "array"
- },
- "system": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
- },
- "targetSteps": {
- "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
- "items": {
- "properties": {
- "isDefault": {
- "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
- "type": "boolean"
- },
- "label": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
- },
- "stepId": {
- "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "stepId",
- "label",
- "isDefault"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "title": {
- "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "id",
- "targetSteps",
- "title",
- "action",
- "role",
- "system",
- "input",
- "output",
- "exceptions",
- "assumptions",
- "openQuestions",
- "confidence",
- "nodeType",
- "nodeSubtype",
- "description",
- "rationale",
- "sources",
- "condition"
- ],
- "type": "object"
- },
- {
- "properties": {
- "action": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
- },
- "assumptions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
- },
- "condition": {
- "description": "Decision criteria evaluated at this gateway. BPMN requires this on every branching gateway. Existing rows persisted with null/empty values parse as \"unknown\" via a read-side preprocess; producers should write a real condition string going forward.",
- "minLength": 1,
- "type": "string"
- },
- "confidence": {
- "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "conflicts": {
- "items": {
- "properties": {
- "id": {
- "minLength": 1,
- "type": "string"
- },
- "mappedVersionIndex": {
- "description": "Zero-based index in versions of the account represented by this step in the current diagram. Omit when unknown. Update or clear it when the diagram or versions change. This records the diagram content, not a resolved conflict.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "question": {
- "minLength": 1,
- "type": "string"
- },
- "versions": {
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "title": {
- "description": "Short heading describing this account; the excerpt remains the exact source quote",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt",
- "captureId"
- ],
- "type": "object"
- },
- "minItems": 2,
- "type": "array"
- }
- },
- "required": [
- "id",
- "question",
- "versions"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "dataObjects": {
- "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
- "items": {
- "properties": {
- "access": {
- "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
- "enum": [
- "read",
- "write"
- ],
- "type": "string"
- },
- "name": {
- "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
- "minLength": 1,
- "type": "string"
- },
- "state": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
- }
- },
- "required": [
- "name",
- "state",
- "access"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "description": {
- "description": "Full prose describing the decision logic at this gateway.",
- "minLength": 1,
- "type": "string"
- },
- "effort": {
- "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
- "items": {
- "properties": {
- "basis": {
- "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
- "enum": [
- "stated",
- "estimated",
- "unknown"
- ],
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
- "minLength": 1,
- "type": "string"
- },
- "frequency": {
- "anyOf": [
- {
- "properties": {
- "count": {
- "description": "How many times the work happens per period. Example: 40",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the count covers. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "count",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "How often the work happens for this person. Null unless they gave a count."
- },
- "person": {
- "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
- "minLength": 1,
- "type": "string"
- },
- "timeSpent": {
- "anyOf": [
- {
- "properties": {
- "hours": {
- "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the hours cover. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "hours",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
- }
- },
- "required": [
- "person",
- "timeSpent",
- "frequency",
- "basis",
- "excerpt"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "exceptions": {
- "description": "Distinct failure modes for this step in display order. Use an empty array when none are documented. Preserve each id when the same exception is edited or regenerated.",
- "items": {
- "properties": {
- "exception": {
- "description": "A distinct failure mode that can happen at this step.",
- "minLength": 1,
- "type": "string"
- },
- "frequency": {
- "anyOf": [
- {
- "enum": [
- "rare",
- "occasional",
- "frequent"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Observed frequency. Null unless evidence explicitly supports rare, occasional, or frequent."
- },
- "handling": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "How the team responds to this exception. Null when the response was not documented."
- },
- "id": {
- "description": "Stable identifier for this exception. Preserve it when the same exception is edited or regenerated. Example: \"exception-po-mismatch\"",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "id",
- "exception",
- "handling",
- "frequency"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "extraCaptureNeeded": {
- "anyOf": [
- {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ]
- },
- "extraCaptureNeeds": {
- "items": {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "id": {
- "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- },
- "input": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
- },
- "laneId": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
- },
- "linkedAgentId": {
- "anyOf": [
- {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
- },
- "nodeSubtype": {
- "description": "BPMN gateway subtype. \"exclusive\" (XOR — exactly one branch taken), \"parallel\" (AND — all branches taken), \"inclusive\" (OR — one or more branches taken).",
- "enum": [
- "exclusive",
- "parallel",
- "inclusive"
- ],
- "type": "string"
- },
- "nodeType": {
- "const": "gateway",
- "type": "string"
- },
- "openQuestions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
- },
- "output": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
- },
- "pool": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
- },
- "rationale": {
- "description": "Why this branching decision exists in the process.",
- "minLength": 1,
- "type": "string"
- },
- "readiness": {
- "anyOf": [
- {
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
- },
- "readinessRationale": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
- },
- "role": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
- },
- "sources": {
- "description": "Evidence supporting the decision criteria.",
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt"
- ],
- "type": "object"
- },
- "minItems": 1,
- "type": "array"
- },
- "system": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
- },
- "targetSteps": {
- "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
- "items": {
- "properties": {
- "isDefault": {
- "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
- "type": "boolean"
- },
- "label": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
- },
- "stepId": {
- "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "stepId",
- "label",
- "isDefault"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "title": {
- "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "id",
- "targetSteps",
- "title",
- "action",
- "role",
- "system",
- "input",
- "output",
- "exceptions",
- "assumptions",
- "openQuestions",
- "confidence",
- "nodeType",
- "nodeSubtype",
- "description",
- "rationale",
- "sources",
- "condition"
- ],
- "type": "object"
- }
- ]
- },
- {
- "oneOf": [
- {
- "additionalProperties": false,
- "properties": {
- "action": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
- },
- "assumptions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
- },
- "condition": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Always null on events; included for shape compatibility across variants."
- },
- "confidence": {
- "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "conflicts": {
- "items": {
- "properties": {
- "id": {
- "minLength": 1,
- "type": "string"
- },
- "mappedVersionIndex": {
- "description": "Zero-based index in versions of the account represented by this step in the current diagram. Omit when unknown. Update or clear it when the diagram or versions change. This records the diagram content, not a resolved conflict.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "question": {
- "minLength": 1,
- "type": "string"
- },
- "versions": {
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "title": {
- "description": "Short heading describing this account; the excerpt remains the exact source quote",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt",
- "captureId"
- ],
- "type": "object"
- },
- "minItems": 2,
- "type": "array"
- }
- },
- "required": [
- "id",
- "question",
- "versions"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "dataObjects": {
- "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
- "items": {
- "properties": {
- "access": {
- "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
- "enum": [
- "read",
- "write"
- ],
- "type": "string"
- },
- "name": {
- "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
- "minLength": 1,
- "type": "string"
- },
- "state": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
- }
- },
- "required": [
- "name",
- "state",
- "access"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "description": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Optional prose describing what happens at this event. May be null for structural markers."
- },
- "effort": {
- "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
- "items": {
- "properties": {
- "basis": {
- "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
- "enum": [
- "stated",
- "estimated",
- "unknown"
- ],
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
- "minLength": 1,
- "type": "string"
- },
- "frequency": {
- "anyOf": [
- {
- "properties": {
- "count": {
- "description": "How many times the work happens per period. Example: 40",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the count covers. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "count",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "How often the work happens for this person. Null unless they gave a count."
- },
- "person": {
- "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
- "minLength": 1,
- "type": "string"
- },
- "timeSpent": {
- "anyOf": [
- {
- "properties": {
- "hours": {
- "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the hours cover. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "hours",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
- }
- },
- "required": [
- "person",
- "timeSpent",
- "frequency",
- "basis",
- "excerpt"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "exception": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Known exceptions, errors, or failure modes observed in the captures for this step. Null when none were mentioned. Example: \"Customer disputes line items or PO number does not match\""
- },
- "extraCaptureNeeded": {
- "anyOf": [
- {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ]
- },
- "extraCaptureNeeds": {
- "items": {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "handling": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "How exceptions or escalations are handled — escalation path, fallback action, or retry strategy. Null when no exception or no handling described. Example: \"Escalate to AP manager via email and pause processing until resolved\""
- },
- "id": {
- "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- },
- "input": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
- },
- "laneId": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
- },
- "linkedAgentId": {
- "anyOf": [
- {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
- },
- "nodeSubtype": {
- "description": "BPMN event subtype. \"start\" (entry trigger), \"end\" (terminal state), \"timer\" (time-based wait; title it with the duration, deadline, or cadence the captures give, e.g. \"Supplier reply: 2-3 days\"), \"message\" (external communication), \"escalation\" (route to higher authority).",
- "enum": [
- "start",
- "end",
- "timer",
- "message",
- "escalation"
- ],
- "type": "string"
- },
- "nodeType": {
- "const": "event",
- "type": "string"
- },
- "openQuestions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
- },
- "output": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
- },
- "pool": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
- },
- "rationale": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Optional reason for the event's existence. May be null for structural markers."
- },
- "readiness": {
- "anyOf": [
- {
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
- },
- "readinessRationale": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
- },
- "role": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
- },
- "sources": {
- "description": "Evidence supporting this event. Empty array allowed (structural markers carry no evidence); non-empty values must follow the source schema.",
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "system": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
- },
- "targetSteps": {
- "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
- "items": {
- "properties": {
- "isDefault": {
- "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
- "type": "boolean"
- },
- "label": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
- },
- "stepId": {
- "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "stepId",
- "label",
- "isDefault"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "title": {
- "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "id",
- "targetSteps",
- "title",
- "action",
- "role",
- "system",
- "input",
- "output",
- "exception",
- "handling",
- "assumptions",
- "openQuestions",
- "confidence",
- "nodeType",
- "nodeSubtype",
- "description",
- "rationale",
- "sources",
- "condition"
- ],
- "type": "object"
- },
- {
- "additionalProperties": false,
- "properties": {
- "action": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
- },
- "assumptions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
- },
- "condition": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Optional precondition that gates this task. Null when the task is unconditional. Example: \"Only when invoice total exceeds $10,000\""
- },
- "confidence": {
- "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "conflicts": {
- "items": {
- "properties": {
- "id": {
- "minLength": 1,
- "type": "string"
- },
- "mappedVersionIndex": {
- "description": "Zero-based index in versions of the account represented by this step in the current diagram. Omit when unknown. Update or clear it when the diagram or versions change. This records the diagram content, not a resolved conflict.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "question": {
- "minLength": 1,
- "type": "string"
- },
- "versions": {
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "title": {
- "description": "Short heading describing this account; the excerpt remains the exact source quote",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt",
- "captureId"
- ],
- "type": "object"
- },
- "minItems": 2,
- "type": "array"
- }
- },
- "required": [
- "id",
- "question",
- "versions"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "dataObjects": {
- "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
- "items": {
- "properties": {
- "access": {
- "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
- "enum": [
- "read",
- "write"
- ],
- "type": "string"
- },
- "name": {
- "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
- "minLength": 1,
- "type": "string"
- },
- "state": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
- }
- },
- "required": [
- "name",
- "state",
- "access"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "description": {
- "description": "Full prose paragraph describing what happens in this step in natural language. Used for documentation reconstruction. Example: \"Finance reviews the invoice in NetSuite, checking line item accuracy and matching against the purchase order before flagging for approval.\"",
- "minLength": 1,
- "type": "string"
- },
- "effort": {
- "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
- "items": {
- "properties": {
- "basis": {
- "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
- "enum": [
- "stated",
- "estimated",
- "unknown"
- ],
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
- "minLength": 1,
- "type": "string"
- },
- "frequency": {
- "anyOf": [
- {
- "properties": {
- "count": {
- "description": "How many times the work happens per period. Example: 40",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the count covers. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "count",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "How often the work happens for this person. Null unless they gave a count."
- },
- "person": {
- "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
- "minLength": 1,
- "type": "string"
- },
- "timeSpent": {
- "anyOf": [
- {
- "properties": {
- "hours": {
- "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the hours cover. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "hours",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
- }
- },
- "required": [
- "person",
- "timeSpent",
- "frequency",
- "basis",
- "excerpt"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "exception": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Known exceptions, errors, or failure modes observed in the captures for this step. Null when none were mentioned. Example: \"Customer disputes line items or PO number does not match\""
- },
- "extraCaptureNeeded": {
- "anyOf": [
- {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ]
- },
- "extraCaptureNeeds": {
- "items": {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "handling": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "How exceptions or escalations are handled — escalation path, fallback action, or retry strategy. Null when no exception or no handling described. Example: \"Escalate to AP manager via email and pause processing until resolved\""
- },
- "id": {
- "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- },
- "input": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
- },
- "laneId": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
- },
- "linkedAgentId": {
- "anyOf": [
- {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
- },
- "nodeSubtype": {
- "description": "BPMN task subtype. \"user\" (human work), \"service\" (automated/API call), \"send\"/\"receive\" (messaging), \"manual\" (offline physical work), \"businessRule\" (rule engine), \"script\" (code execution).",
- "enum": [
- "user",
- "service",
- "send",
- "receive",
- "manual",
- "businessRule",
- "script"
- ],
- "type": "string"
- },
- "nodeType": {
- "const": "task",
- "type": "string"
- },
- "openQuestions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
- },
- "output": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
- },
- "pool": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
- },
- "rationale": {
- "description": "Why this step exists in the process — its purpose or business reason. Used by downstream agents to assess whether the step is essential or removable. Example: \"Catches mispriced line items before they reach the customer and prevents downstream credit notes.\"",
- "minLength": 1,
- "type": "string"
- },
- "readiness": {
- "anyOf": [
- {
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
- },
- "readinessRationale": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
- },
- "role": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
- },
- "sources": {
- "description": "Evidence supporting this step's existence and details. At least one source is required — every step must trace back to something in the captures.",
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt"
- ],
- "type": "object"
- },
- "minItems": 1,
- "type": "array"
- },
- "system": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
- },
- "targetSteps": {
- "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
- "items": {
- "properties": {
- "isDefault": {
- "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
- "type": "boolean"
- },
- "label": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
- },
- "stepId": {
- "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "stepId",
- "label",
- "isDefault"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "title": {
- "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "id",
- "targetSteps",
- "title",
- "action",
- "role",
- "system",
- "input",
- "output",
- "exception",
- "handling",
- "assumptions",
- "openQuestions",
- "confidence",
- "nodeType",
- "nodeSubtype",
- "description",
- "rationale",
- "sources",
- "condition"
- ],
- "type": "object"
- },
- {
- "additionalProperties": false,
- "properties": {
- "action": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
- },
- "assumptions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
- },
- "condition": {
- "description": "Decision criteria evaluated at this gateway. BPMN requires this on every branching gateway. Existing rows persisted with null/empty values parse as \"unknown\" via a read-side preprocess; producers should write a real condition string going forward.",
- "minLength": 1,
- "type": "string"
- },
- "confidence": {
- "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "conflicts": {
- "items": {
- "properties": {
- "id": {
- "minLength": 1,
- "type": "string"
- },
- "mappedVersionIndex": {
- "description": "Zero-based index in versions of the account represented by this step in the current diagram. Omit when unknown. Update or clear it when the diagram or versions change. This records the diagram content, not a resolved conflict.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "question": {
- "minLength": 1,
- "type": "string"
- },
- "versions": {
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- "title": {
- "description": "Short heading describing this account; the excerpt remains the exact source quote",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt",
- "captureId"
- ],
- "type": "object"
- },
- "minItems": 2,
- "type": "array"
- }
- },
- "required": [
- "id",
- "question",
- "versions"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "dataObjects": {
- "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
- "items": {
- "properties": {
- "access": {
- "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
- "enum": [
- "read",
- "write"
- ],
- "type": "string"
- },
- "name": {
- "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
- "minLength": 1,
- "type": "string"
- },
- "state": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
- }
- },
- "required": [
- "name",
- "state",
- "access"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "description": {
- "description": "Full prose describing the decision logic at this gateway.",
- "minLength": 1,
- "type": "string"
- },
- "effort": {
- "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
- "items": {
- "properties": {
- "basis": {
- "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
- "enum": [
- "stated",
- "estimated",
- "unknown"
- ],
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
- "minLength": 1,
- "type": "string"
- },
- "frequency": {
- "anyOf": [
- {
- "properties": {
- "count": {
- "description": "How many times the work happens per period. Example: 40",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the count covers. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "count",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "How often the work happens for this person. Null unless they gave a count."
- },
- "person": {
- "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
- "minLength": 1,
- "type": "string"
- },
- "timeSpent": {
- "anyOf": [
- {
- "properties": {
- "hours": {
- "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
- "exclusiveMinimum": 0,
- "type": "number"
- },
- "period": {
- "description": "Period the hours cover. Example: \"day\"",
- "enum": [
- "day",
- "week",
- "month"
- ],
- "type": "string"
- }
- },
- "required": [
- "hours",
- "period"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ],
- "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
- }
- },
- "required": [
- "person",
- "timeSpent",
- "frequency",
- "basis",
- "excerpt"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "exception": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Known exceptions, errors, or failure modes observed in the captures for this step. Null when none were mentioned. Example: \"Customer disputes line items or PO number does not match\""
- },
- "extraCaptureNeeded": {
- "anyOf": [
- {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- {
- "type": "null"
- }
- ]
- },
- "extraCaptureNeeds": {
- "items": {
- "properties": {
- "gap": {
- "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
- "minLength": 1,
- "type": "string"
- },
- "id": {
- "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- "proposal": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
- }
- },
- "required": [
- "id",
- "gap"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "handling": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "How exceptions or escalations are handled — escalation path, fallback action, or retry strategy. Null when no exception or no handling described. Example: \"Escalate to AP manager via email and pause processing until resolved\""
- },
- "id": {
- "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- },
- "input": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
- },
- "laneId": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
- },
- "linkedAgentId": {
- "anyOf": [
- {
- "format": "uuid",
- "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
- },
- "nodeSubtype": {
- "description": "BPMN gateway subtype. \"exclusive\" (XOR — exactly one branch taken), \"parallel\" (AND — all branches taken), \"inclusive\" (OR — one or more branches taken).",
- "enum": [
- "exclusive",
- "parallel",
- "inclusive"
- ],
- "type": "string"
- },
- "nodeType": {
- "const": "gateway",
- "type": "string"
- },
- "openQuestions": {
- "anyOf": [
- {
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- {
- "type": "null"
- }
- ],
- "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
- },
- "output": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
- },
- "pool": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
- },
- "rationale": {
- "description": "Why this branching decision exists in the process.",
- "minLength": 1,
- "type": "string"
- },
- "readiness": {
- "anyOf": [
- {
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
- },
- "readinessRationale": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
- },
- "role": {
- "anyOf": [
- {
- "minLength": 1,
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
- },
- "sources": {
- "description": "Evidence supporting the decision criteria.",
- "items": {
- "properties": {
- "attribution": {
- "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
- "minLength": 1,
- "type": "string"
- },
- "captureId": {
- "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
- "minLength": 1,
- "type": "string"
- },
- "evidenceId": {
- "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
- "minLength": 1,
- "type": "string"
- },
- "excerpt": {
- "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
- "minLength": 1,
- "type": "string"
- },
- "locator": {
- "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
- "oneOf": [
- {
- "properties": {
- "messageIndex": {
- "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "timestampMs": {
- "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "transcript_message",
- "type": "string"
- }
- },
- "required": [
- "type",
- "messageIndex"
- ],
- "type": "object"
- },
- {
- "properties": {
- "endLine": {
- "description": "Optional one-based line number where the cited text ends on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "endOffset": {
- "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "pageNumber": {
- "description": "Optional one-based PDF page number when the stored capture has page metadata.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startLine": {
- "description": "Optional one-based line number where the cited text starts on pageNumber.",
- "exclusiveMinimum": 0,
- "maximum": 9007199254740991,
- "type": "integer"
- },
- "startOffset": {
- "description": "Zero-based character offset into the stored capture text.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "document_text_range",
- "type": "string"
- }
- },
- "required": [
- "type",
- "startOffset",
- "endOffset"
- ],
- "type": "object"
- },
- {
- "properties": {
- "elementId": {
- "description": "BPMN XML element id within an uploaded .bpmn document.",
- "minLength": 1,
- "type": "string"
- },
- "elementType": {
- "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
- "minLength": 1,
- "type": "string"
- },
- "name": {
- "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "bpmn_element",
- "type": "string"
- }
- },
- "required": [
- "type",
- "elementId"
- ],
- "type": "object"
- },
- {
- "properties": {
- "timestampMs": {
- "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
- "maximum": 9007199254740991,
- "minimum": 0,
- "type": "integer"
- },
- "type": {
- "const": "screenshare_frame",
- "type": "string"
- }
- },
- "required": [
- "type",
- "timestampMs"
- ],
- "type": "object"
- },
- {
- "properties": {
- "type": {
- "const": "manual",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- },
- {
- "properties": {
- "reason": {
- "minLength": 1,
- "type": "string"
- },
- "type": {
- "const": "unresolved",
- "type": "string"
- }
- },
- "required": [
- "type"
- ],
- "type": "object"
- }
- ]
- },
- "resolutionStatus": {
- "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
- "enum": [
- "resolved",
- "unresolved",
- "legacy",
- "manual"
- ],
- "type": "string"
- },
- "sourceConfidence": {
- "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
- "enum": [
- "low",
- "medium",
- "high"
- ],
- "type": "string"
- }
- },
- "required": [
- "attribution",
- "excerpt"
- ],
- "type": "object"
- },
- "minItems": 1,
- "type": "array"
- },
- "system": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
- },
- "targetSteps": {
- "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
- "items": {
- "properties": {
- "isDefault": {
- "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
- "type": "boolean"
- },
- "label": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
- },
- "stepId": {
- "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "stepId",
- "label",
- "isDefault"
- ],
- "type": "object"
- },
- "type": "array"
- },
- "title": {
- "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "id",
- "targetSteps",
- "title",
- "action",
- "role",
- "system",
- "input",
- "output",
- "exception",
- "handling",
- "assumptions",
- "openQuestions",
- "confidence",
- "nodeType",
- "nodeSubtype",
- "description",
- "rationale",
- "sources",
- "condition"
- ],
- "type": "object"
- }
- ]
- }
-]New value: +[
+ {
+ "oneOf": [
+ {
+ "properties": {
+ "action": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
+ },
+ "assumptions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
+ },
+ "condition": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Always null on events; included for shape compatibility across variants."
+ },
+ "confidence": {
+ "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ "dataObjects": {
+ "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
+ "items": {
+ "properties": {
+ "access": {
+ "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
+ "enum": [
+ "read",
+ "write"
+ ],
+ "type": "string"
+ },
+ "name": {
+ "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "state": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
+ }
+ },
+ "required": [
+ "name",
+ "state",
+ "access"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "description": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Optional prose describing what happens at this event. May be null for structural markers."
+ },
+ "effort": {
+ "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
+ "items": {
+ "properties": {
+ "basis": {
+ "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
+ "enum": [
+ "stated",
+ "estimated",
+ "unknown"
+ ],
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "frequency": {
+ "anyOf": [
+ {
+ "properties": {
+ "count": {
+ "description": "How many times the work happens per period. Example: 40",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the count covers. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "count",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How often the work happens for this person. Null unless they gave a count."
+ },
+ "person": {
+ "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "timeSpent": {
+ "anyOf": [
+ {
+ "properties": {
+ "hours": {
+ "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the hours cover. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "hours",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
+ }
+ },
+ "required": [
+ "person",
+ "timeSpent",
+ "frequency",
+ "basis",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "exceptions": {
+ "description": "Distinct failure modes for this step in display order. Use an empty array when none are documented. Preserve each id when the same exception is edited or regenerated.",
+ "items": {
+ "properties": {
+ "exception": {
+ "description": "A distinct failure mode that can happen at this step.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "frequency": {
+ "anyOf": [
+ {
+ "enum": [
+ "rare",
+ "occasional",
+ "frequent"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Observed frequency. Null unless evidence explicitly supports rare, occasional, or frequent."
+ },
+ "handling": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How the team responds to this exception. Null when the response was not documented."
+ },
+ "id": {
+ "description": "Stable identifier for this exception. Preserve it when the same exception is edited or regenerated. Example: \"exception-po-mismatch\"",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "exception",
+ "handling",
+ "frequency"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "extraCaptureNeeded": {
+ "anyOf": [
+ {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "extraCaptureNeeds": {
+ "items": {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "id": {
+ "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "input": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
+ },
+ "laneId": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
+ },
+ "linkedAgentId": {
+ "anyOf": [
+ {
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
+ },
+ "nodeSubtype": {
+ "description": "BPMN event subtype. \"start\" (entry trigger), \"end\" (terminal state), \"timer\" (time-based wait; title it with the duration, deadline, or cadence the captures give, e.g. \"Supplier reply: 2-3 days\"), \"message\" (external communication), \"escalation\" (route to higher authority).",
+ "enum": [
+ "start",
+ "end",
+ "timer",
+ "message",
+ "escalation"
+ ],
+ "type": "string"
+ },
+ "nodeType": {
+ "const": "event",
+ "type": "string"
+ },
+ "openQuestions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
+ },
+ "output": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
+ },
+ "pool": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
+ },
+ "rationale": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Optional reason for the event's existence. May be null for structural markers."
+ },
+ "readiness": {
+ "anyOf": [
+ {
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
+ },
+ "readinessRationale": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
+ },
+ "role": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
+ },
+ "sources": {
+ "description": "Evidence supporting this event. Empty array allowed (structural markers carry no evidence); non-empty values must follow the source schema.",
+ "items": {
+ "properties": {
+ "attribution": {
+ "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "evidenceId": {
+ "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "locator": {
+ "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
+ "oneOf": [
+ {
+ "properties": {
+ "messageIndex": {
+ "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "timestampMs": {
+ "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "transcript_message",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "messageIndex"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "endLine": {
+ "description": "Optional one-based line number where the cited text ends on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "endOffset": {
+ "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "pageNumber": {
+ "description": "Optional one-based PDF page number when the stored capture has page metadata.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startLine": {
+ "description": "Optional one-based line number where the cited text starts on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startOffset": {
+ "description": "Zero-based character offset into the stored capture text.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "document_text_range",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "startOffset",
+ "endOffset"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "elementId": {
+ "description": "BPMN XML element id within an uploaded .bpmn document.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "elementType": {
+ "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
+ "minLength": 1,
+ "type": "string"
+ },
+ "name": {
+ "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "bpmn_element",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "elementId"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "timestampMs": {
+ "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "screenshare_frame",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "timestampMs"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "manual",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "reason": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "unresolved",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ }
+ ]
+ },
+ "resolutionStatus": {
+ "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
+ "enum": [
+ "resolved",
+ "unresolved",
+ "legacy",
+ "manual"
+ ],
+ "type": "string"
+ },
+ "sourceConfidence": {
+ "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "attribution",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "system": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
+ },
+ "targetSteps": {
+ "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
+ "items": {
+ "properties": {
+ "isDefault": {
+ "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
+ "type": "boolean"
+ },
+ "label": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
+ },
+ "stepId": {
+ "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "stepId",
+ "label",
+ "isDefault"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "title": {
+ "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "targetSteps",
+ "title",
+ "action",
+ "role",
+ "system",
+ "input",
+ "output",
+ "exceptions",
+ "assumptions",
+ "openQuestions",
+ "confidence",
+ "nodeType",
+ "nodeSubtype",
+ "description",
+ "rationale",
+ "sources",
+ "condition"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "action": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
+ },
+ "assumptions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
+ },
+ "condition": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Optional precondition that gates this task. Null when the task is unconditional. Example: \"Only when invoice total exceeds $10,000\""
+ },
+ "confidence": {
+ "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ "dataObjects": {
+ "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
+ "items": {
+ "properties": {
+ "access": {
+ "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
+ "enum": [
+ "read",
+ "write"
+ ],
+ "type": "string"
+ },
+ "name": {
+ "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "state": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
+ }
+ },
+ "required": [
+ "name",
+ "state",
+ "access"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "description": {
+ "description": "Full prose paragraph describing what happens in this step in natural language. Used for documentation reconstruction. Example: \"Finance reviews the invoice in NetSuite, checking line item accuracy and matching against the purchase order before flagging for approval.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "effort": {
+ "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
+ "items": {
+ "properties": {
+ "basis": {
+ "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
+ "enum": [
+ "stated",
+ "estimated",
+ "unknown"
+ ],
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "frequency": {
+ "anyOf": [
+ {
+ "properties": {
+ "count": {
+ "description": "How many times the work happens per period. Example: 40",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the count covers. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "count",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How often the work happens for this person. Null unless they gave a count."
+ },
+ "person": {
+ "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "timeSpent": {
+ "anyOf": [
+ {
+ "properties": {
+ "hours": {
+ "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the hours cover. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "hours",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
+ }
+ },
+ "required": [
+ "person",
+ "timeSpent",
+ "frequency",
+ "basis",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "exceptions": {
+ "description": "Distinct failure modes for this step in display order. Use an empty array when none are documented. Preserve each id when the same exception is edited or regenerated.",
+ "items": {
+ "properties": {
+ "exception": {
+ "description": "A distinct failure mode that can happen at this step.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "frequency": {
+ "anyOf": [
+ {
+ "enum": [
+ "rare",
+ "occasional",
+ "frequent"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Observed frequency. Null unless evidence explicitly supports rare, occasional, or frequent."
+ },
+ "handling": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How the team responds to this exception. Null when the response was not documented."
+ },
+ "id": {
+ "description": "Stable identifier for this exception. Preserve it when the same exception is edited or regenerated. Example: \"exception-po-mismatch\"",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "exception",
+ "handling",
+ "frequency"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "extraCaptureNeeded": {
+ "anyOf": [
+ {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "extraCaptureNeeds": {
+ "items": {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "id": {
+ "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "input": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
+ },
+ "laneId": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
+ },
+ "linkedAgentId": {
+ "anyOf": [
+ {
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
+ },
+ "nodeSubtype": {
+ "description": "BPMN task subtype. \"user\" (human work), \"service\" (automated/API call), \"send\"/\"receive\" (messaging), \"manual\" (offline physical work), \"businessRule\" (rule engine), \"script\" (code execution).",
+ "enum": [
+ "user",
+ "service",
+ "send",
+ "receive",
+ "manual",
+ "businessRule",
+ "script"
+ ],
+ "type": "string"
+ },
+ "nodeType": {
+ "const": "task",
+ "type": "string"
+ },
+ "openQuestions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
+ },
+ "output": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
+ },
+ "pool": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
+ },
+ "rationale": {
+ "description": "Why this step exists in the process — its purpose or business reason. Used by downstream agents to assess whether the step is essential or removable. Example: \"Catches mispriced line items before they reach the customer and prevents downstream credit notes.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "readiness": {
+ "anyOf": [
+ {
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
+ },
+ "readinessRationale": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
+ },
+ "role": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
+ },
+ "sources": {
+ "description": "Evidence supporting this step's existence and details. At least one source is required — every step must trace back to something in the captures.",
+ "items": {
+ "properties": {
+ "attribution": {
+ "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "evidenceId": {
+ "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "locator": {
+ "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
+ "oneOf": [
+ {
+ "properties": {
+ "messageIndex": {
+ "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "timestampMs": {
+ "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "transcript_message",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "messageIndex"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "endLine": {
+ "description": "Optional one-based line number where the cited text ends on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "endOffset": {
+ "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "pageNumber": {
+ "description": "Optional one-based PDF page number when the stored capture has page metadata.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startLine": {
+ "description": "Optional one-based line number where the cited text starts on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startOffset": {
+ "description": "Zero-based character offset into the stored capture text.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "document_text_range",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "startOffset",
+ "endOffset"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "elementId": {
+ "description": "BPMN XML element id within an uploaded .bpmn document.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "elementType": {
+ "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
+ "minLength": 1,
+ "type": "string"
+ },
+ "name": {
+ "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "bpmn_element",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "elementId"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "timestampMs": {
+ "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "screenshare_frame",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "timestampMs"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "manual",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "reason": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "unresolved",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ }
+ ]
+ },
+ "resolutionStatus": {
+ "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
+ "enum": [
+ "resolved",
+ "unresolved",
+ "legacy",
+ "manual"
+ ],
+ "type": "string"
+ },
+ "sourceConfidence": {
+ "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "attribution",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "minItems": 1,
+ "type": "array"
+ },
+ "system": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
+ },
+ "targetSteps": {
+ "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
+ "items": {
+ "properties": {
+ "isDefault": {
+ "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
+ "type": "boolean"
+ },
+ "label": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
+ },
+ "stepId": {
+ "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "stepId",
+ "label",
+ "isDefault"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "title": {
+ "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "targetSteps",
+ "title",
+ "action",
+ "role",
+ "system",
+ "input",
+ "output",
+ "exceptions",
+ "assumptions",
+ "openQuestions",
+ "confidence",
+ "nodeType",
+ "nodeSubtype",
+ "description",
+ "rationale",
+ "sources",
+ "condition"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "action": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
+ },
+ "assumptions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
+ },
+ "condition": {
+ "description": "Decision criteria evaluated at this gateway. BPMN requires this on every branching gateway. Existing rows persisted with null/empty values parse as \"unknown\" via a read-side preprocess; producers should write a real condition string going forward.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "confidence": {
+ "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ "dataObjects": {
+ "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
+ "items": {
+ "properties": {
+ "access": {
+ "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
+ "enum": [
+ "read",
+ "write"
+ ],
+ "type": "string"
+ },
+ "name": {
+ "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "state": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
+ }
+ },
+ "required": [
+ "name",
+ "state",
+ "access"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "description": {
+ "description": "Full prose describing the decision logic at this gateway.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "effort": {
+ "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
+ "items": {
+ "properties": {
+ "basis": {
+ "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
+ "enum": [
+ "stated",
+ "estimated",
+ "unknown"
+ ],
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "frequency": {
+ "anyOf": [
+ {
+ "properties": {
+ "count": {
+ "description": "How many times the work happens per period. Example: 40",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the count covers. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "count",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How often the work happens for this person. Null unless they gave a count."
+ },
+ "person": {
+ "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "timeSpent": {
+ "anyOf": [
+ {
+ "properties": {
+ "hours": {
+ "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the hours cover. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "hours",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
+ }
+ },
+ "required": [
+ "person",
+ "timeSpent",
+ "frequency",
+ "basis",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "exceptions": {
+ "description": "Distinct failure modes for this step in display order. Use an empty array when none are documented. Preserve each id when the same exception is edited or regenerated.",
+ "items": {
+ "properties": {
+ "exception": {
+ "description": "A distinct failure mode that can happen at this step.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "frequency": {
+ "anyOf": [
+ {
+ "enum": [
+ "rare",
+ "occasional",
+ "frequent"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Observed frequency. Null unless evidence explicitly supports rare, occasional, or frequent."
+ },
+ "handling": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How the team responds to this exception. Null when the response was not documented."
+ },
+ "id": {
+ "description": "Stable identifier for this exception. Preserve it when the same exception is edited or regenerated. Example: \"exception-po-mismatch\"",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "exception",
+ "handling",
+ "frequency"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "extraCaptureNeeded": {
+ "anyOf": [
+ {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "extraCaptureNeeds": {
+ "items": {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "id": {
+ "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "input": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
+ },
+ "laneId": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
+ },
+ "linkedAgentId": {
+ "anyOf": [
+ {
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
+ },
+ "nodeSubtype": {
+ "description": "BPMN gateway subtype. \"exclusive\" (XOR — exactly one branch taken), \"parallel\" (AND — all branches taken), \"inclusive\" (OR — one or more branches taken).",
+ "enum": [
+ "exclusive",
+ "parallel",
+ "inclusive"
+ ],
+ "type": "string"
+ },
+ "nodeType": {
+ "const": "gateway",
+ "type": "string"
+ },
+ "openQuestions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
+ },
+ "output": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
+ },
+ "pool": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
+ },
+ "rationale": {
+ "description": "Why this branching decision exists in the process.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "readiness": {
+ "anyOf": [
+ {
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
+ },
+ "readinessRationale": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
+ },
+ "role": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
+ },
+ "sources": {
+ "description": "Evidence supporting the decision criteria.",
+ "items": {
+ "properties": {
+ "attribution": {
+ "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "evidenceId": {
+ "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "locator": {
+ "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
+ "oneOf": [
+ {
+ "properties": {
+ "messageIndex": {
+ "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "timestampMs": {
+ "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "transcript_message",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "messageIndex"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "endLine": {
+ "description": "Optional one-based line number where the cited text ends on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "endOffset": {
+ "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "pageNumber": {
+ "description": "Optional one-based PDF page number when the stored capture has page metadata.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startLine": {
+ "description": "Optional one-based line number where the cited text starts on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startOffset": {
+ "description": "Zero-based character offset into the stored capture text.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "document_text_range",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "startOffset",
+ "endOffset"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "elementId": {
+ "description": "BPMN XML element id within an uploaded .bpmn document.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "elementType": {
+ "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
+ "minLength": 1,
+ "type": "string"
+ },
+ "name": {
+ "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "bpmn_element",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "elementId"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "timestampMs": {
+ "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "screenshare_frame",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "timestampMs"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "manual",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "reason": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "unresolved",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ }
+ ]
+ },
+ "resolutionStatus": {
+ "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
+ "enum": [
+ "resolved",
+ "unresolved",
+ "legacy",
+ "manual"
+ ],
+ "type": "string"
+ },
+ "sourceConfidence": {
+ "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "attribution",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "minItems": 1,
+ "type": "array"
+ },
+ "system": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
+ },
+ "targetSteps": {
+ "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
+ "items": {
+ "properties": {
+ "isDefault": {
+ "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
+ "type": "boolean"
+ },
+ "label": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
+ },
+ "stepId": {
+ "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "stepId",
+ "label",
+ "isDefault"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "title": {
+ "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "targetSteps",
+ "title",
+ "action",
+ "role",
+ "system",
+ "input",
+ "output",
+ "exceptions",
+ "assumptions",
+ "openQuestions",
+ "confidence",
+ "nodeType",
+ "nodeSubtype",
+ "description",
+ "rationale",
+ "sources",
+ "condition"
+ ],
+ "type": "object"
+ }
+ ]
+ },
+ {
+ "oneOf": [
+ {
+ "additionalProperties": false,
+ "properties": {
+ "action": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
+ },
+ "assumptions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
+ },
+ "condition": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Always null on events; included for shape compatibility across variants."
+ },
+ "confidence": {
+ "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ "dataObjects": {
+ "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
+ "items": {
+ "properties": {
+ "access": {
+ "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
+ "enum": [
+ "read",
+ "write"
+ ],
+ "type": "string"
+ },
+ "name": {
+ "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "state": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
+ }
+ },
+ "required": [
+ "name",
+ "state",
+ "access"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "description": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Optional prose describing what happens at this event. May be null for structural markers."
+ },
+ "effort": {
+ "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
+ "items": {
+ "properties": {
+ "basis": {
+ "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
+ "enum": [
+ "stated",
+ "estimated",
+ "unknown"
+ ],
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "frequency": {
+ "anyOf": [
+ {
+ "properties": {
+ "count": {
+ "description": "How many times the work happens per period. Example: 40",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the count covers. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "count",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How often the work happens for this person. Null unless they gave a count."
+ },
+ "person": {
+ "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "timeSpent": {
+ "anyOf": [
+ {
+ "properties": {
+ "hours": {
+ "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the hours cover. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "hours",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
+ }
+ },
+ "required": [
+ "person",
+ "timeSpent",
+ "frequency",
+ "basis",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "exception": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Known exceptions, errors, or failure modes observed in the captures for this step. Null when none were mentioned. Example: \"Customer disputes line items or PO number does not match\""
+ },
+ "extraCaptureNeeded": {
+ "anyOf": [
+ {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "extraCaptureNeeds": {
+ "items": {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "handling": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How exceptions or escalations are handled — escalation path, fallback action, or retry strategy. Null when no exception or no handling described. Example: \"Escalate to AP manager via email and pause processing until resolved\""
+ },
+ "id": {
+ "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "input": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
+ },
+ "laneId": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
+ },
+ "linkedAgentId": {
+ "anyOf": [
+ {
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
+ },
+ "nodeSubtype": {
+ "description": "BPMN event subtype. \"start\" (entry trigger), \"end\" (terminal state), \"timer\" (time-based wait; title it with the duration, deadline, or cadence the captures give, e.g. \"Supplier reply: 2-3 days\"), \"message\" (external communication), \"escalation\" (route to higher authority).",
+ "enum": [
+ "start",
+ "end",
+ "timer",
+ "message",
+ "escalation"
+ ],
+ "type": "string"
+ },
+ "nodeType": {
+ "const": "event",
+ "type": "string"
+ },
+ "openQuestions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
+ },
+ "output": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
+ },
+ "pool": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
+ },
+ "rationale": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Optional reason for the event's existence. May be null for structural markers."
+ },
+ "readiness": {
+ "anyOf": [
+ {
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
+ },
+ "readinessRationale": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
+ },
+ "role": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
+ },
+ "sources": {
+ "description": "Evidence supporting this event. Empty array allowed (structural markers carry no evidence); non-empty values must follow the source schema.",
+ "items": {
+ "properties": {
+ "attribution": {
+ "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "evidenceId": {
+ "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "locator": {
+ "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
+ "oneOf": [
+ {
+ "properties": {
+ "messageIndex": {
+ "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "timestampMs": {
+ "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "transcript_message",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "messageIndex"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "endLine": {
+ "description": "Optional one-based line number where the cited text ends on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "endOffset": {
+ "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "pageNumber": {
+ "description": "Optional one-based PDF page number when the stored capture has page metadata.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startLine": {
+ "description": "Optional one-based line number where the cited text starts on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startOffset": {
+ "description": "Zero-based character offset into the stored capture text.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "document_text_range",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "startOffset",
+ "endOffset"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "elementId": {
+ "description": "BPMN XML element id within an uploaded .bpmn document.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "elementType": {
+ "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
+ "minLength": 1,
+ "type": "string"
+ },
+ "name": {
+ "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "bpmn_element",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "elementId"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "timestampMs": {
+ "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "screenshare_frame",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "timestampMs"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "manual",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "reason": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "unresolved",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ }
+ ]
+ },
+ "resolutionStatus": {
+ "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
+ "enum": [
+ "resolved",
+ "unresolved",
+ "legacy",
+ "manual"
+ ],
+ "type": "string"
+ },
+ "sourceConfidence": {
+ "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "attribution",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "system": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
+ },
+ "targetSteps": {
+ "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
+ "items": {
+ "properties": {
+ "isDefault": {
+ "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
+ "type": "boolean"
+ },
+ "label": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
+ },
+ "stepId": {
+ "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "stepId",
+ "label",
+ "isDefault"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "title": {
+ "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "targetSteps",
+ "title",
+ "action",
+ "role",
+ "system",
+ "input",
+ "output",
+ "exception",
+ "handling",
+ "assumptions",
+ "openQuestions",
+ "confidence",
+ "nodeType",
+ "nodeSubtype",
+ "description",
+ "rationale",
+ "sources",
+ "condition"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "properties": {
+ "action": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
+ },
+ "assumptions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
+ },
+ "condition": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Optional precondition that gates this task. Null when the task is unconditional. Example: \"Only when invoice total exceeds $10,000\""
+ },
+ "confidence": {
+ "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ "dataObjects": {
+ "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
+ "items": {
+ "properties": {
+ "access": {
+ "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
+ "enum": [
+ "read",
+ "write"
+ ],
+ "type": "string"
+ },
+ "name": {
+ "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "state": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
+ }
+ },
+ "required": [
+ "name",
+ "state",
+ "access"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "description": {
+ "description": "Full prose paragraph describing what happens in this step in natural language. Used for documentation reconstruction. Example: \"Finance reviews the invoice in NetSuite, checking line item accuracy and matching against the purchase order before flagging for approval.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "effort": {
+ "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
+ "items": {
+ "properties": {
+ "basis": {
+ "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
+ "enum": [
+ "stated",
+ "estimated",
+ "unknown"
+ ],
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "frequency": {
+ "anyOf": [
+ {
+ "properties": {
+ "count": {
+ "description": "How many times the work happens per period. Example: 40",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the count covers. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "count",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How often the work happens for this person. Null unless they gave a count."
+ },
+ "person": {
+ "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "timeSpent": {
+ "anyOf": [
+ {
+ "properties": {
+ "hours": {
+ "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the hours cover. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "hours",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
+ }
+ },
+ "required": [
+ "person",
+ "timeSpent",
+ "frequency",
+ "basis",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "exception": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Known exceptions, errors, or failure modes observed in the captures for this step. Null when none were mentioned. Example: \"Customer disputes line items or PO number does not match\""
+ },
+ "extraCaptureNeeded": {
+ "anyOf": [
+ {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "extraCaptureNeeds": {
+ "items": {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "handling": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How exceptions or escalations are handled — escalation path, fallback action, or retry strategy. Null when no exception or no handling described. Example: \"Escalate to AP manager via email and pause processing until resolved\""
+ },
+ "id": {
+ "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "input": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
+ },
+ "laneId": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
+ },
+ "linkedAgentId": {
+ "anyOf": [
+ {
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
+ },
+ "nodeSubtype": {
+ "description": "BPMN task subtype. \"user\" (human work), \"service\" (automated/API call), \"send\"/\"receive\" (messaging), \"manual\" (offline physical work), \"businessRule\" (rule engine), \"script\" (code execution).",
+ "enum": [
+ "user",
+ "service",
+ "send",
+ "receive",
+ "manual",
+ "businessRule",
+ "script"
+ ],
+ "type": "string"
+ },
+ "nodeType": {
+ "const": "task",
+ "type": "string"
+ },
+ "openQuestions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
+ },
+ "output": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
+ },
+ "pool": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
+ },
+ "rationale": {
+ "description": "Why this step exists in the process — its purpose or business reason. Used by downstream agents to assess whether the step is essential or removable. Example: \"Catches mispriced line items before they reach the customer and prevents downstream credit notes.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "readiness": {
+ "anyOf": [
+ {
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
+ },
+ "readinessRationale": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
+ },
+ "role": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
+ },
+ "sources": {
+ "description": "Evidence supporting this step's existence and details. At least one source is required — every step must trace back to something in the captures.",
+ "items": {
+ "properties": {
+ "attribution": {
+ "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "evidenceId": {
+ "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "locator": {
+ "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
+ "oneOf": [
+ {
+ "properties": {
+ "messageIndex": {
+ "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "timestampMs": {
+ "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "transcript_message",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "messageIndex"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "endLine": {
+ "description": "Optional one-based line number where the cited text ends on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "endOffset": {
+ "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "pageNumber": {
+ "description": "Optional one-based PDF page number when the stored capture has page metadata.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startLine": {
+ "description": "Optional one-based line number where the cited text starts on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startOffset": {
+ "description": "Zero-based character offset into the stored capture text.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "document_text_range",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "startOffset",
+ "endOffset"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "elementId": {
+ "description": "BPMN XML element id within an uploaded .bpmn document.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "elementType": {
+ "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
+ "minLength": 1,
+ "type": "string"
+ },
+ "name": {
+ "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "bpmn_element",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "elementId"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "timestampMs": {
+ "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "screenshare_frame",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "timestampMs"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "manual",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "reason": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "unresolved",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ }
+ ]
+ },
+ "resolutionStatus": {
+ "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
+ "enum": [
+ "resolved",
+ "unresolved",
+ "legacy",
+ "manual"
+ ],
+ "type": "string"
+ },
+ "sourceConfidence": {
+ "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "attribution",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "minItems": 1,
+ "type": "array"
+ },
+ "system": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
+ },
+ "targetSteps": {
+ "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
+ "items": {
+ "properties": {
+ "isDefault": {
+ "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
+ "type": "boolean"
+ },
+ "label": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
+ },
+ "stepId": {
+ "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "stepId",
+ "label",
+ "isDefault"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "title": {
+ "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "targetSteps",
+ "title",
+ "action",
+ "role",
+ "system",
+ "input",
+ "output",
+ "exception",
+ "handling",
+ "assumptions",
+ "openQuestions",
+ "confidence",
+ "nodeType",
+ "nodeSubtype",
+ "description",
+ "rationale",
+ "sources",
+ "condition"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "properties": {
+ "action": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Verb-led one-liner summarizing the concrete action performed. Example: \"Reviews invoice line items in NetSuite against the purchase order.\""
+ },
+ "assumptions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Assumptions the LLM made when extracting this step that were not directly stated in captures. Null if none. Used by verification agents to flag risky inferences. Example: [\"Invoices are reviewed within 24 hours of receipt\"]"
+ },
+ "condition": {
+ "description": "Decision criteria evaluated at this gateway. BPMN requires this on every branching gateway. Existing rows persisted with null/empty values parse as \"unknown\" via a read-side preprocess; producers should write a real condition string going forward.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "confidence": {
+ "description": "Confidence in the accuracy of this step given evidence quality and completeness. \"high\" = directly stated by multiple sources, \"medium\" = stated by one source or inferred from strong signals, \"low\" = inferred with significant assumptions.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ "dataObjects": {
+ "description": "Documents or records this step reads or writes, such as an invoice, a purchase order, or a price list. The process map draws each distinct name and state once and links it to every step that lists it. Omit or use an empty array when the captures name none.",
+ "items": {
+ "properties": {
+ "access": {
+ "description": "\"read\" when the step uses the object as input; \"write\" when the step creates or updates it.",
+ "enum": [
+ "read",
+ "write"
+ ],
+ "type": "string"
+ },
+ "name": {
+ "description": "Name of the document or record, as the captures call it. Use the exact same name on every step that touches the same object. Examples: \"Invoice\", \"Purchase order\", \"Price list\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "state": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "State the object is in at this step, only when the captures name one. Null otherwise. Examples: \"approved\", \"draft\", null"
+ }
+ },
+ "required": [
+ "name",
+ "state",
+ "access"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "description": {
+ "description": "Full prose describing the decision logic at this gateway.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "effort": {
+ "description": "Time each interviewee spends on this step, one entry per person per capture. Omit when no interviewee spoke to this step's time or frequency.",
+ "items": {
+ "properties": {
+ "basis": {
+ "description": "\"stated\" = the person gave the number; \"estimated\" = they gave or accepted a rough guess when pressed; \"unknown\" = they were asked but gave no figure, so timeSpent and frequency are both null.",
+ "enum": [
+ "stated",
+ "estimated",
+ "unknown"
+ ],
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id of the interview the figure came from. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim quote the figure comes from. Example: \"Probably two hours every morning, more at month end.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "frequency": {
+ "anyOf": [
+ {
+ "properties": {
+ "count": {
+ "description": "How many times the work happens per period. Example: 40",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the count covers. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "count",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How often the work happens for this person. Null unless they gave a count."
+ },
+ "person": {
+ "description": "Who reported this effort, matching the source attribution. Example: \"Anna, AP Clerk\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "timeSpent": {
+ "anyOf": [
+ {
+ "properties": {
+ "hours": {
+ "description": "Hours this person spends on the work per period. Use one best value; for a range (\"1 to 2 hours\") use the midpoint and keep the range in excerpt. Example: 2",
+ "exclusiveMinimum": 0,
+ "type": "number"
+ },
+ "period": {
+ "description": "Period the hours cover. Example: \"day\"",
+ "enum": [
+ "day",
+ "week",
+ "month"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "hours",
+ "period"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Time this person spends on the work. Null when they gave no time figure; whether they were asked is carried by basis (\"unknown\" when asked and both figures are null)."
+ }
+ },
+ "required": [
+ "person",
+ "timeSpent",
+ "frequency",
+ "basis",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "exception": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Known exceptions, errors, or failure modes observed in the captures for this step. Null when none were mentioned. Example: \"Customer disputes line items or PO number does not match\""
+ },
+ "extraCaptureNeeded": {
+ "anyOf": [
+ {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "extraCaptureNeeds": {
+ "items": {
+ "properties": {
+ "gap": {
+ "description": "Plain-language description of what about this step is unknown or under-specified, blocking automation. One short sentence. Example: \"We don't know which fields the AP analyst copies from the invoice into NetSuite.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "id": {
+ "description": "Id of the `clarity_proposal_extra_capture_request` row this slot points at. Created server-side by the agent after the LLM call; the LLM never produces this value.",
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ "proposal": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What the new capture should include in order to resolve the gap — concrete actions, screens, or decisions the user should walk through. Optional: omit when no specific proposal can be inferred. Example: \"Walk through reviewing one invoice in NetSuite end-to-end while narrating each field you check.\""
+ }
+ },
+ "required": [
+ "id",
+ "gap"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "handling": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "How exceptions or escalations are handled — escalation path, fallback action, or retry strategy. Null when no exception or no handling described. Example: \"Escalate to AP manager via email and pause processing until resolved\""
+ },
+ "id": {
+ "description": "Stable identifier for the step. Referenced by targetSteps[].stepId and by postprocessing agents annotating specific steps. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "input": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Information or artifacts required to start this step. Null on start events or steps with no preconditions. Example: \"Invoice PDF and matching purchase order number\""
+ },
+ "laneId": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the lane in the snapshot's lanes array that performs this step. Null when the step has no role. The server keeps it in step with `role`."
+ },
+ "linkedAgentId": {
+ "anyOf": [
+ {
+ "format": "uuid",
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Id of the Duvo Agent that performs this step. Set by a person in edit mode, never by a generating or postprocessing agent; the save route rejects an id that is not a live Agent on the process's team."
+ },
+ "nodeSubtype": {
+ "description": "BPMN gateway subtype. \"exclusive\" (XOR — exactly one branch taken), \"parallel\" (AND — all branches taken), \"inclusive\" (OR — one or more branches taken).",
+ "enum": [
+ "exclusive",
+ "parallel",
+ "inclusive"
+ ],
+ "type": "string"
+ },
+ "nodeType": {
+ "const": "gateway",
+ "type": "string"
+ },
+ "openQuestions": {
+ "anyOf": [
+ {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Specific gaps in understanding that a follow-up capture should address. Null if none. Drives the next interview or document request. Example: [\"Is there a backup approver when the AP manager is out of office?\"]"
+ },
+ "output": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "What this step produces or updates. Null on pure waits or events that emit nothing. Example: \"Approved invoice record in NetSuite with reviewer signature\""
+ },
+ "pool": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "The organization or party outside the process owner's own organization that performs this step, such as \"Supplier\", \"Customer\", \"Bank\", or \"Tax authority\". The process map draws each party as its own pool, with its roles as lanes inside it. Null for every step the process owner's own organization performs, which is most of them. Use one spelling per party, and give every step of one role the same pool."
+ },
+ "rationale": {
+ "description": "Why this branching decision exists in the process.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "readiness": {
+ "anyOf": [
+ {
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Automation-readiness rating for this step. \"high\" = fully automatable today, \"medium\" = partially automatable or needs minor changes, \"low\" = blocked by manual review, judgement, or missing data."
+ },
+ "readinessRationale": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "One-sentence justification for the readiness rating, citing the specific signals that drove the choice. Example: \"Requires human judgement on edge cases that are not documented in the captures.\""
+ },
+ "role": {
+ "anyOf": [
+ {
+ "minLength": 1,
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Performer of this step — the specific job title, team, or system. Use \"Duvo\" for automated actions and \"System\" for system-triggered steps. The process map draws one lane per distinct role, so decide the process's roles once and give every step a role performs the exact same text; never combine two roles in one value such as \"Buyer or Commercial\". Examples: \"Finance Analyst\", \"Sales Operations\", \"Duvo\", \"System\""
+ },
+ "sources": {
+ "description": "Evidence supporting the decision criteria.",
+ "items": {
+ "properties": {
+ "attribution": {
+ "description": "Human-readable source label identifying who or what the evidence comes from. Examples: \"Anna (sales interview)\", \"Onboarding SOP §3.2\", \"Slack #ops 2024-06-12\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "captureId": {
+ "description": "Durable clarity_capture id for this source. Use app-owned ids from the evidence index, never sandbox file paths.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "evidenceId": {
+ "description": "Stable id of the evidence unit from /workspace/captures/evidence-index.json when generation used that index.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "excerpt": {
+ "description": "Verbatim supporting text quoted from the capture, document, or transcript. Example: \"We always wait for finance to sign off before sending the invoice.\"",
+ "minLength": 1,
+ "type": "string"
+ },
+ "locator": {
+ "description": "Durable in-capture location for the excerpt. Missing means legacy free-text source; unresolved means a structured citation was attempted but could not be resolved.",
+ "oneOf": [
+ {
+ "properties": {
+ "messageIndex": {
+ "description": "Zero-based index into the capture transcript message array. This is the durable key; timestampMs is only supplemental.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "timestampMs": {
+ "description": "Optional epoch-millisecond timestamp for the transcript message when the capture supplied one.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "transcript_message",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "messageIndex"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "endLine": {
+ "description": "Optional one-based line number where the cited text ends on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "endOffset": {
+ "description": "Exclusive character offset into the stored capture text. Must be greater than startOffset.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "pageNumber": {
+ "description": "Optional one-based PDF page number when the stored capture has page metadata.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startLine": {
+ "description": "Optional one-based line number where the cited text starts on pageNumber.",
+ "exclusiveMinimum": 0,
+ "maximum": 9007199254740991,
+ "type": "integer"
+ },
+ "startOffset": {
+ "description": "Zero-based character offset into the stored capture text.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "document_text_range",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "startOffset",
+ "endOffset"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "elementId": {
+ "description": "BPMN XML element id within an uploaded .bpmn document.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "elementType": {
+ "description": "Optional BPMN element type as parsed from the XML, for example \"bpmn:UserTask\" or \"bpmn:ExclusiveGateway\".",
+ "minLength": 1,
+ "type": "string"
+ },
+ "name": {
+ "description": "Optional BPMN element name as parsed from the XML. The element id is the durable key.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "bpmn_element",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "elementId"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "timestampMs": {
+ "description": "Epoch-millisecond frame timestamp matching a screenshare frame filename.",
+ "maximum": 9007199254740991,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "type": {
+ "const": "screenshare_frame",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "timestampMs"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "manual",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ },
+ {
+ "properties": {
+ "reason": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "type": {
+ "const": "unresolved",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ }
+ ]
+ },
+ "resolutionStatus": {
+ "description": "Resolution status for the structured source link. Legacy sources may omit this field.",
+ "enum": [
+ "resolved",
+ "unresolved",
+ "legacy",
+ "manual"
+ ],
+ "type": "string"
+ },
+ "sourceConfidence": {
+ "description": "Confidence in this individual source citation. \"high\" = direct quote at the locator, \"medium\" = strong nearby evidence, \"low\" = weak or inferred support.",
+ "enum": [
+ "low",
+ "medium",
+ "high"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "attribution",
+ "excerpt"
+ ],
+ "type": "object"
+ },
+ "minItems": 1,
+ "type": "array"
+ },
+ "system": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "System, tool, or application used to perform this step. Null when the step is purely manual or is a decision/event with no associated tool. Examples: \"NetSuite\", \"Gmail\", \"Excel\", null"
+ },
+ "targetSteps": {
+ "description": "Outgoing BPMN edges from this step. Empty array only on end events. Exclusive and inclusive gateways that branch must have ≥2 entries with exactly one isDefault: true; a merge gateway (≥2 incoming paths) has exactly 1 entry.",
+ "items": {
+ "properties": {
+ "isDefault": {
+ "description": "True on exactly one outgoing edge of a branching exclusive or inclusive gateway, marking the fallback taken when no other condition matches. False on all other edges, including the single edge leaving a merge gateway.",
+ "type": "boolean"
+ },
+ "label": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Human-readable label shown on the BPMN edge. For gateways, the outcome answer; for default flows, \"Otherwise\"; for an edge into another role's lane or another party's pool, what is handed over and how. Examples: \"Approved\", \"> $5k\", \"Otherwise\", \"Signed contract, by email\""
+ },
+ "stepId": {
+ "description": "Id of the step this edge points to. Must match an existing step.id in the same steps array. Example: \"step-review-invoice\"",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "stepId",
+ "label",
+ "isDefault"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "title": {
+ "description": "Required node label used in lists and BPMN node labels. Structural markers use defaults such as \"Start\" and \"End\".",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "targetSteps",
+ "title",
+ "action",
+ "role",
+ "system",
+ "input",
+ "output",
+ "exception",
+ "handling",
+ "assumptions",
+ "openQuestions",
+ "confidence",
+ "nodeType",
+ "nodeSubtype",
+ "description",
+ "rationale",
+ "sources",
+ "condition"
+ ],
+ "type": "object"
+ }
+ ]
+ }
+]