chore: merge develop preserving documentation structure and console UX

Integrate develop at 523bade3 while retaining concise agent guidance, rustdoc-owned design rationale, and current console history/rewind behavior. Adapt incoming tests to public entry-ID rewind and synchronize OpenAPI/TypeScript artifacts.

Validation: default-member cargo test --all-features (4936 passed, 23 ignored), root cargo check, all-feature rustdoc with broken links denied, format/diff/name guards, OpenAPI and 11 TypeScript freshness checks. Web: 613 unit, 327 component, 7 Ticket browser and 3 Console browser tests; check/build passed. Merged-state Ticket visual review at 1440/768/390px in light/dark; no matching pre-merge image baseline. E2E/live-provider checks not run.
This commit is contained in:
2026-10-13 02:46:50 +09:00
213 changed files with 59018 additions and 14443 deletions
File diff suppressed because it is too large Load Diff
@@ -438,6 +438,34 @@ fn validate_ticket_browser_operations(
paths: &Map<String, Value>,
) -> Result<BTreeSet<String>, GenerationError> {
let operations = [
OperationContract {
path: "/api/w/{workspace_id}/ticket-tags",
method: "get",
operation_id: "workspace_ticket_tag_list",
request: None,
successes: &[("200", "Array_of_WorkspaceTag")],
},
OperationContract {
path: "/api/w/{workspace_id}/ticket-tags",
method: "post",
operation_id: "workspace_ticket_tag_mutate",
request: Some("WorkspaceTagMutation"),
successes: &[("200", "WorkspaceTag")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/{id}/tags",
method: "put",
operation_id: "ticket_tags_set",
request: Some("TicketTagSetRequest"),
successes: &[("200", "Array_of_WorkspaceTag")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/query",
method: "post",
operation_id: "ticket_query",
request: Some("TicketQueryRequest"),
successes: &[("200", "TicketQueryResponse")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets",
method: "get",
@@ -481,11 +509,74 @@ fn validate_ticket_browser_operations(
successes: &[("200", "TicketDetail")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/{id}/state",
path: "/workspaces/{workspace_id}/tickets/{ticket_id}/case",
method: "post",
operation_id: "ticket_state_transition",
request: Some("BrowserTransitionTicketStateRequest"),
successes: &[("200", "TicketDetail")],
operation_id: "ticket_case_update",
request: Some("TicketCaseUpdateRequest"),
successes: &[("200", "TicketSummary")],
},
OperationContract {
path: "/workspaces/{workspace_id}/tickets/{ticket_id}/assignment-tracking/assignments",
method: "get",
operation_id: "ticket_assignments_page",
request: None,
successes: &[("200", "TicketAssignmentsPage")],
},
OperationContract {
path: "/workspaces/{workspace_id}/tickets/{ticket_id}/assignment-diagnostics",
method: "get",
operation_id: "ticket_assignment_diagnostics",
request: None,
successes: &[("200", "TicketAssignmentDiagnosticsPage")],
},
OperationContract {
path: "/workspaces/{workspace_id}/tickets/{ticket_id}/assignment-answer",
method: "post",
operation_id: "ticket_assignment_answer",
request: Some("TicketAssignmentAnswer"),
successes: &[("200", "TicketAssignmentAnswerReceipt")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/{ticket_id}/assignment-tracking/assignments",
method: "get",
operation_id: "ticket_assignments_page_browser",
request: None,
successes: &[("200", "TicketAssignmentsPage")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/{ticket_id}/assignment-diagnostics",
method: "get",
operation_id: "ticket_assignment_diagnostics_browser",
request: None,
successes: &[("200", "TicketAssignmentDiagnosticsPage")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/{ticket_id}/assignment-answer",
method: "post",
operation_id: "ticket_assignment_answer_browser",
request: Some("TicketAssignmentAnswer"),
successes: &[("200", "TicketAssignmentAnswerReceipt")],
},
OperationContract {
path: "/workspaces/{workspace_id}/tickets/{ticket_id}/assignment-tracking",
method: "get",
operation_id: "ticket_assignment_tracking_get",
request: None,
successes: &[("200", "Array_of_TicketAssignmentTrackingProjection")],
},
OperationContract {
path: "/workspaces/{workspace_id}/tickets/{ticket_id}/assignment-tracking",
method: "post",
operation_id: "ticket_assignment_tracking_update",
request: Some("TicketAssignmentTrackingUpdate"),
successes: &[("200", "TicketAssignmentTrackingProjection")],
},
OperationContract {
path: "/workspaces/{workspace_id}/tickets/{ticket_id}/assignment-tracking/history",
method: "get",
operation_id: "ticket_assignment_tracking_history",
request: None,
successes: &[("200", "TicketAssignmentTrackingHistoryPage")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/{id}/ready",
@@ -508,13 +599,6 @@ fn validate_ticket_browser_operations(
request: Some("BrowserQueueTicketRequest"),
successes: &[("200", "TicketQueueOutcome")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/{id}/close",
method: "post",
operation_id: "ticket_close",
request: Some("BrowserCloseTicketRequest"),
successes: &[("200", "TicketDetail")],
},
OperationContract {
path: "/api/w/{workspace_id}/objectives",
method: "get",
@@ -1906,6 +1990,54 @@ mod tests {
assert!(!detail.contains(" target:"));
}
#[test]
fn ticket_browser_generator_exposes_case_judgment_and_closure_projections() {
let openapi = crate::canonical_openapi_document()
.unwrap()
.to_json()
.unwrap();
let output = generate_ticket_browser_typescript(&openapi).unwrap();
assert!(output.contains("export type BrowserTicketState = \"open\" | \"closed\";"));
let request = output
.lines()
.find(|line| line.starts_with("export type TicketCaseUpdateRequest ="))
.unwrap();
for field in [
"expected_content_digest: string",
"expected_state: TicketState",
"expected_closure_operation_key: string | null",
"operation_key: string",
"action: TicketCaseAction",
"explanation: string",
] {
assert!(request.contains(field), "missing {field}: {request}");
}
assert!(!request.contains("author"));
assert!(output.contains("export type TicketClosureReason = \"completed\" | \"not_planned\" | \"duplicate\" | \"unknown\" | { other: string; };"));
let detail = output
.lines()
.find(|line| line.starts_with("export type TicketDetail ="))
.unwrap();
for field in [
"state: BrowserTicketState",
"closure_operation_key?: string | null",
"current_closure?: TicketClosureJudgment | null",
"closure_history: Array<TicketCaseHistoryEntry>",
"legacy_handoff?: TicketLegacyWorkflowSnapshot | null",
] {
assert!(detail.contains(field), "missing {field}: {detail}");
}
for removed in [
"BrowserTransitionTicketStateRequest",
"BrowserCloseTicketRequest",
"CompleteTicketRequest",
"BrowserTicketWorkflowState",
"done_not_closed",
] {
assert!(!output.contains(removed), "{removed}");
}
}
#[test]
fn checked_in_ticket_browser_typescript_is_current() {
assert_eq!(