// Support's commands. syntax = "proto3"; package pharos.support.v1; option go_package = "github.com/pharos-ai-factory/pharos-platform/services/beto/contracts/requests/generated/pharos/support/v1;supportv1"; import "pharos/contracts/v1/requests.proto"; // CreateTicket opens the acting user's ticket, whose ID the browser chose, with // its opening message. message CreateTicket { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PUBLIC response: "pharos.requests.v1.Outcome" }; optional string title = 1 [(pharos.contracts.v1.required_input) = true]; optional string body = 2 [(pharos.contracts.v1.required_input) = true]; // Removed Run-to-ticket references; existing ticket messages retain their text. reserved 3 to 7; reserved "project_id", "run_id", "repository_type", "repository_name", "run_kind"; } // CloseTicket asks to close the acting user's ticket. message CloseTicket { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PUBLIC response: "pharos.requests.v1.Outcome" }; } // AddMessage writes the acting user's message, whose ID the browser chose, on // one of their tickets. message AddMessage { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PUBLIC response: "pharos.requests.v1.Outcome" }; optional string ticket_id = 1 [(pharos.contracts.v1.required_input) = true]; optional string body = 2 [(pharos.contracts.v1.required_input) = true]; } // RequestCustomerLink links a Pharos user to a support service customer. Only // the operator's CLI credential may send it, until users are registered. An // empty email means none is verified yet: the link awaits a contact, and a // later request with an email resumes it. message RequestCustomerLink { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PUBLIC response: "pharos.requests.v1.Outcome" }; optional string email = 1 [(pharos.contracts.v1.required_input) = true]; optional string first_name = 2 [(pharos.contracts.v1.required_input) = true]; optional string last_name = 3 [(pharos.contracts.v1.required_input) = true]; } // Support's private commands; the API never sends them. A reaction queues each // one after any support service call; the webhook and the support-retry job run // the last three directly. Stored command bytes are durable: keep field numbers // stable. // RecordFilingResultCommand records the support service's ticket, or why it // was not filed. Exactly one of support_service_ticket_id and failure_reason. message RecordFilingResultCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional string support_service_ticket_id = 1; optional string support_service_number = 2; optional string support_service_message_id = 3; optional string failure_reason = 4; } // RecordOpeningMessageCommand records a ticket's first message, dated with the ticket. message RecordOpeningMessageCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional string ticket_id = 1 [(pharos.contracts.v1.required_input) = true]; optional string user_id = 2 [(pharos.contracts.v1.required_input) = true]; optional string body = 3 [(pharos.contracts.v1.required_input) = true]; optional string ticket_created_at = 4 [(pharos.contracts.v1.required_input) = true]; } // MarkOpeningMessageDeliveredCommand: the opening message reached the support // service with its ticket. message MarkOpeningMessageDeliveredCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional string support_service_message_id = 1 [(pharos.contracts.v1.required_input) = true]; } // DispatchMessageCommand claims the ticket's oldest waiting message for // sending, or fails it with failure_reason when the ticket never reached the // support service. message DispatchMessageCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional string failure_reason = 1; } // RecordMessageResultCommand records the support service's message, or why it // was not posted. Exactly one of the two. message RecordMessageResultCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional string support_service_message_id = 1; optional string failure_reason = 2; } // RecordCloseResultCommand records that the support service closed the ticket // (as of support_service_updated_at there), or why it did not. message RecordCloseResultCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional string support_service_updated_at = 1; optional string failure_reason = 2; } // AgentReply is a support agent's public message read from the support service. message AgentReply { optional string support_service_message_id = 1 [(pharos.contracts.v1.required_input) = true]; optional string author = 2 [(pharos.contracts.v1.required_input) = true]; optional string body = 3 [(pharos.contracts.v1.required_input) = true]; optional string written_at = 4 [(pharos.contracts.v1.required_input) = true]; } // RecordSupportServiceReadCommand records one re-read of a ticket: its state // there (or that it is no longer shown to Pharos) and its agent replies. message RecordSupportServiceReadCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; bool withdrawn = 1; bool closed = 2; optional string updated_at = 3; repeated AgentReply replies = 4; } // ApplySupportServiceStateCommand brings the ticket in step with the support // service: closed or reopened as of updated_at, or withdrawn. message ApplySupportServiceStateCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; bool withdrawn = 1; bool closed = 2; optional string updated_at = 3; } // ReceiveAgentMessageCommand records an imported agent reply as a message. message ReceiveAgentMessageCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional string ticket_id = 1 [(pharos.contracts.v1.required_input) = true]; optional string user_id = 2 [(pharos.contracts.v1.required_input) = true]; optional string author = 3 [(pharos.contracts.v1.required_input) = true]; optional string body = 4 [(pharos.contracts.v1.required_input) = true]; optional string support_service_message_id = 5 [(pharos.contracts.v1.required_input) = true]; optional string written_at = 6 [(pharos.contracts.v1.required_input) = true]; } // RecordLinkResultCommand records the support service customer found, claimed // or created (result "linked"), an unreachable service ("failed") or a problem // for a person ("conflict"). message RecordLinkResultCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional string result = 1 [(pharos.contracts.v1.required_input) = true]; optional string support_service_user_id = 2; optional string reason = 3; } // RequestSyncCommand records that the support service may have changed a ticket. message RequestSyncCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; } // ReleaseMessageCommand returns a claim held too long to pending. message ReleaseMessageCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; } // RetryCustomerLinkCommand starts another attempt for a due link, with the // contact details last recorded for the user. message RetryCustomerLinkCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional string email = 1 [(pharos.contracts.v1.required_input) = true]; optional string first_name = 2 [(pharos.contracts.v1.required_input) = true]; optional string last_name = 3 [(pharos.contracts.v1.required_input) = true]; } // RecordContactResultCommand records whether the linked customer took the // contact at revision ("synced"), the service was unreachable ("failed") or a // person must act ("conflict"). message RecordContactResultCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional uint64 revision = 1 [(pharos.contracts.v1.required_input) = true]; optional string result = 2 [(pharos.contracts.v1.required_input) = true]; optional string reason = 3; } // RetryCustomerContactCommand gives the linked customer the recorded contact // again when its update is due. message RetryCustomerContactCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; } // ApplyPartyContactCommand applies a registered Party's verified contact to its // link, at Party Governance's attributes revision. Revision 0 only registers the // Party: its link waits for a verified email. Email is empty when none is verified. message ApplyPartyContactCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional uint64 revision = 1 [(pharos.contracts.v1.required_input) = true]; optional string email = 2 [(pharos.contracts.v1.required_input) = true]; optional string first_name = 3 [(pharos.contracts.v1.required_input) = true]; optional string last_name = 4 [(pharos.contracts.v1.required_input) = true]; } // ApplyPartyAccessCommand records whether a Party may sign in, at Party // Governance's authentication revision (auth_version). A disabled Party's // customer may not sign in to the support service. message ApplyPartyAccessCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional uint64 revision = 1 [(pharos.contracts.v1.required_input) = true]; optional bool active = 2 [(pharos.contracts.v1.required_input) = true]; } // RecordAccessResultCommand records what changing the customer's sign-in at // revision achieved: synced, failed or conflict (with a reason). message RecordAccessResultCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; optional uint64 revision = 1 [(pharos.contracts.v1.required_input) = true]; optional string result = 2 [(pharos.contracts.v1.required_input) = true]; optional string reason = 3; } // RetryCustomerAccessCommand changes the customer's sign-in again when that is due. message RetryCustomerAccessCommand { option (pharos.contracts.v1.contract) = { owner: "support" visibility: PRIVATE response: "pharos.requests.v1.Outcome" }; }