Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .pa/task_arch10d.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ARCH-10d — Task- und Control-Routen nach hq_routes

Status: entwurf

Paketgröße: M, höchstens 300 Diff-Zeilen
Dateien: `src-tauri/src/api.rs`, `src-tauri/src/api/hq_routes.rs`, dieser Auftrag

Verschiebt unverändert die fünf Arme `GET|POST /api/hq/v1/tasks/:id/assignment`,
`POST /api/hq/v1/tasks/:id/claim`, `POST /api/hq/v1/tasks/:id/checkpoint` und
`POST /api/hq/v1/control` aus `api.rs` in `hq_routes::handle()`. Der Besitztest
in `hq_routes::route` nennt genau diese Methoden und Pfadsegmente, kein Präfix-
oder Methoden-Platzhalter. Damit ist ARCH-10 abgeschlossen.

Keine neue Funktion, kein Bugfix, keine Änderung an Backend, Store, Schema,
Auth oder Konfiguration. Bestehende API-Tests in `api.rs` decken Verhalten und
Reihenfolge ab (No-Test, rein mechanisch).
83 changes: 0 additions & 83 deletions src-tauri/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1386,89 +1386,6 @@ fn route(inner: &Inner, request: &Request, proof: VerdictProof) -> Response {
}

match (method, path.as_slice()) {
("GET", ["api", "hq", "v1", "tasks", task_id, "assignment"]) => {
match backend.continuous_task_assignment(task_id) {
Ok(assignment) => Response::ok(
json!({"apiVersion":1,"source":"rust/sqlite","assignment":assignment,"approvalAuthority":false}),
),
Err(error) => continuous_error(error),
}
}
("POST", ["api", "hq", "v1", "tasks", task_id, "assignment"]) => {
let body = match serde_json::from_str::<crate::store::team_assignments::AssignmentRequest>(
&request.body,
) {
Ok(body) => body,
Err(error) => {
return Response::error(400, format!("invalid team assignment: {error}"))
}
};
match backend.assign_continuous_task(task_id, body) {
Ok(assignment) => Response::ok(
json!({"apiVersion":1,"source":"rust/sqlite","assignment":assignment,"approvalAuthority":false}),
),
Err(error) => continuous_error(error),
}
}
("POST", ["api", "hq", "v1", "tasks", task_id, "claim"]) => {
let body = match parse_body(&request.body) {
Ok(body) => body,
Err(err) => return Response::error(400, err),
};
let owner = match required_str(&body, "owner") {
Ok(value) => value,
Err(err) => return Response::error(400, err),
};
let escalation = body
.get("escalation")
.and_then(Value::as_bool)
.unwrap_or(false);
match backend.claim_continuous_task(task_id, &owner, escalation) {
Ok(claim) => Response::ok(json!({ "claim": claim })),
Err(err) => continuous_error(err),
}
}
("POST", ["api", "hq", "v1", "tasks", task_id, "checkpoint"]) => {
let body = match parse_body(&request.body) {
Ok(body) => body,
Err(err) => return Response::error(400, err),
};
let owner = match required_str(&body, "owner") {
Ok(value) => value,
Err(err) => return Response::error(400, err),
};
let fence = match body.get("fence").and_then(Value::as_i64) {
Some(value) if value > 0 => value,
_ => return Response::error(400, "fence must be a positive integer"),
};
let status = body
.get("status")
.and_then(Value::as_str)
.map(str::to_string);
let detail = body
.get("detail")
.and_then(Value::as_str)
.map(str::to_string);
match backend.checkpoint_continuous_task(task_id, &owner, fence, status, detail) {
Ok(task) => Response::ok(json!({ "task": task })),
Err(err) => continuous_error(err),
}
}
("POST", ["api", "hq", "v1", "control"]) => {
let body = match parse_body(&request.body) {
Ok(body) => body,
Err(err) => return Response::error(400, err),
};
let project_id = match required_str(&body, "projectId") {
Ok(value) => value,
Err(err) => return Response::error(400, err),
};
let action = match required_str(&body, "action") {
Ok(value) => value,
Err(err) => return Response::error(400, err),
};
continuous_response(backend.control_continuous(&project_id, &action))
}
("GET", ["api", "health"]) => Response::ok(json!({ "ok": true })),

("GET", ["api", "diagnosis"]) => {
Expand Down
92 changes: 92 additions & 0 deletions src-tauri/src/api/hq_routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ pub(super) fn route(
| ("POST", ["api", "hq", "v1", "plan", "import"])
| ("GET" | "POST", ["api", "hq", "v1", "goals"])
| ("POST", ["api", "hq", "v1", "goals", _, "tasks"])
| (
"GET" | "POST",
["api", "hq", "v1", "tasks", _, "assignment"]
)
| (
"POST",
["api", "hq", "v1", "tasks", _, "claim" | "checkpoint"]
)
| ("POST", ["api", "hq", "v1", "control"])
);
owned.then(|| handle(inner, request, method, path, project_id))
}
Expand Down Expand Up @@ -253,6 +262,89 @@ fn handle(
Err(err) => continuous_error(err),
}
}
("GET", ["api", "hq", "v1", "tasks", task_id, "assignment"]) => {
match backend.continuous_task_assignment(task_id) {
Ok(assignment) => Response::ok(
json!({"apiVersion":1,"source":"rust/sqlite","assignment":assignment,"approvalAuthority":false}),
),
Err(error) => continuous_error(error),
}
}
("POST", ["api", "hq", "v1", "tasks", task_id, "assignment"]) => {
let body = match serde_json::from_str::<crate::store::team_assignments::AssignmentRequest>(
&request.body,
) {
Ok(body) => body,
Err(error) => {
return Response::error(400, format!("invalid team assignment: {error}"))
}
};
match backend.assign_continuous_task(task_id, body) {
Ok(assignment) => Response::ok(
json!({"apiVersion":1,"source":"rust/sqlite","assignment":assignment,"approvalAuthority":false}),
),
Err(error) => continuous_error(error),
}
}
("POST", ["api", "hq", "v1", "tasks", task_id, "claim"]) => {
let body = match parse_body(&request.body) {
Ok(body) => body,
Err(err) => return Response::error(400, err),
};
let owner = match required_str(&body, "owner") {
Ok(value) => value,
Err(err) => return Response::error(400, err),
};
let escalation = body
.get("escalation")
.and_then(Value::as_bool)
.unwrap_or(false);
match backend.claim_continuous_task(task_id, &owner, escalation) {
Ok(claim) => Response::ok(json!({ "claim": claim })),
Err(err) => continuous_error(err),
}
}
("POST", ["api", "hq", "v1", "tasks", task_id, "checkpoint"]) => {
let body = match parse_body(&request.body) {
Ok(body) => body,
Err(err) => return Response::error(400, err),
};
let owner = match required_str(&body, "owner") {
Ok(value) => value,
Err(err) => return Response::error(400, err),
};
let fence = match body.get("fence").and_then(Value::as_i64) {
Some(value) if value > 0 => value,
_ => return Response::error(400, "fence must be a positive integer"),
};
let status = body
.get("status")
.and_then(Value::as_str)
.map(str::to_string);
let detail = body
.get("detail")
.and_then(Value::as_str)
.map(str::to_string);
match backend.checkpoint_continuous_task(task_id, &owner, fence, status, detail) {
Ok(task) => Response::ok(json!({ "task": task })),
Err(err) => continuous_error(err),
}
}
("POST", ["api", "hq", "v1", "control"]) => {
let body = match parse_body(&request.body) {
Ok(body) => body,
Err(err) => return Response::error(400, err),
};
let project_id = match required_str(&body, "projectId") {
Ok(value) => value,
Err(err) => return Response::error(400, err),
};
let action = match required_str(&body, "action") {
Ok(value) => value,
Err(err) => return Response::error(400, err),
};
continuous_response(backend.control_continuous(&project_id, &action))
}
_ => unreachable!("route() only hands over owned arms"),
}
}
Loading