syntax = "proto3"; package taskforge.tickets.v1; import "google/api/annotations.proto"; service TicketsService { rpc SubmitJob(SubmitJobRequest) returns (JobAccepted) { option (google.api.http) = { post: "/tickets/v1/jobs" body: "*" additional_bindings { post: "/v1/task-generation/jobs" body: "*" } }; } rpc GetJob(GetJobRequest) returns (TicketJob) { option (google.api.http) = { get: "/tickets/v1/jobs/{job_id}" }; } rpc GetJobResult(GetJobResultRequest) returns (TicketResultResponse) { option (google.api.http) = { get: "/tickets/v1/jobs/{job_id}/result" }; } rpc ListJobs(ListJobsRequest) returns (ListJobsResponse) { option (google.api.http) = { get: "/tickets/v1/jobs" }; } rpc CancelJob(CancelJobRequest) returns (TicketJob) { option (google.api.http) = { delete: "/tickets/v1/jobs/{job_id}" }; } rpc GetSchema(GetSchemaRequest) returns (SchemaResponse) { option (google.api.http) = { get: "/tickets/v1/schema" }; } } message SubmitJobRequest { string schema_version = 1; string idempotency_key = 2; string title = 3; string spec = 4; TicketGenerationOptions options = 5; string callback_url = 6; } message TicketGenerationOptions { uint32 ticket_count = 1; uint32 max_ticket_count = 2; bool include_epics = 3; // Allowed value: explicit. string dependency_mode = 4; // Allowed values: compact, standard, detailed. string output_detail = 5; } message JobAccepted { string schema_version = 1; string job_id = 2; string status = 3; string status_url = 4; string result_url = 5; string created_at = 6; } message TicketJob { string schema_version = 1; string job_id = 2; string status = 3; string stage = 4; string created_at = 5; string updated_at = 6; string expires_at = 7; JobError error = 8; } message JobError { string code = 1; string message = 2; } message TicketResultResponse { string schema_version = 1; string job_id = 2; SourceSummary source = 3; repeated Ticket tickets = 4; repeated Risk risks = 5; repeated OpenQuestion open_questions = 6; GenerationMetadata generation = 7; } message SourceSummary { string title = 1; string summary = 2; } message Ticket { string external_id = 1; string ticket_type = 2; string title = 3; string description = 4; repeated string acceptance_criteria = 5; repeated string labels = 6; repeated string dependencies = 7; optional int32 story_points = 8; optional string priority = 9; optional string parent_external_id = 10; TicketMetadata metadata = 11; } message TicketMetadata { string component = 1; string suggested_milestone = 2; double confidence = 3; } message Risk { string id = 1; string description = 2; string severity = 3; repeated string related_ticket_ids = 4; } message OpenQuestion { string id = 1; string question = 2; repeated string related_ticket_ids = 3; } message GenerationMetadata { string model = 1; uint64 duration_ms = 2; optional uint32 prompt_tokens = 3; optional uint32 completion_tokens = 4; optional string finish_reason = 5; } message GetJobRequest { string job_id = 1; } message GetJobResultRequest { string job_id = 1; } message ListJobsRequest { uint32 limit = 1; string status = 2; } message ListJobsResponse { repeated TicketJob jobs = 1; } message CancelJobRequest { string job_id = 1; } message GetSchemaRequest {} message SchemaResponse { string input_schema_version = 1; string result_schema_version = 2; string schema_json = 3; }