fix: validate assignment runtime snapshots
This commit is contained in:
@@ -5237,8 +5237,9 @@ fn workspace_resource_reference_diagnostics(conn: &Connection) -> Result<Vec<Str
|
|||||||
AND ticket.ticket_id = link.ticket_id) LIMIT 100",
|
AND ticket.ticket_id = link.ticket_id) LIMIT 100",
|
||||||
),
|
),
|
||||||
// Historical assignment/operation rows intentionally survive Ticket or Worker
|
// Historical assignment/operation rows intentionally survive Ticket or Worker
|
||||||
// retention deletion. A parent missing from every Workspace is therefore a retained
|
// retention deletion. A parent id missing from every Workspace is therefore a retained
|
||||||
// soft reference; a matching id that exists only in another Workspace is corruption.
|
// soft reference; a matching Ticket id in another Workspace, or a live Worker id whose
|
||||||
|
// Workspace/Runtime placement does not match the snapshot, is corruption.
|
||||||
(
|
(
|
||||||
"ticket_worker_assignments.ticket_id",
|
"ticket_worker_assignments.ticket_id",
|
||||||
"SELECT assignment.workspace_id || '/' || assignment.assignment_id || ' -> ' || assignment.ticket_id \
|
"SELECT assignment.workspace_id || '/' || assignment.assignment_id || ' -> ' || assignment.ticket_id \
|
||||||
@@ -5255,9 +5256,10 @@ fn workspace_resource_reference_diagnostics(conn: &Connection) -> Result<Vec<Str
|
|||||||
FROM ticket_worker_assignments AS assignment \
|
FROM ticket_worker_assignments AS assignment \
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM worker_registry AS worker \
|
WHERE NOT EXISTS (SELECT 1 FROM worker_registry AS worker \
|
||||||
WHERE worker.workspace_id = assignment.workspace_id \
|
WHERE worker.workspace_id = assignment.workspace_id \
|
||||||
|
AND worker.runtime_id = assignment.runtime_id \
|
||||||
AND worker.worker_id = assignment.worker_id) \
|
AND worker.worker_id = assignment.worker_id) \
|
||||||
AND EXISTS (SELECT 1 FROM worker_registry AS foreign_worker \
|
AND EXISTS (SELECT 1 FROM worker_registry AS live_worker \
|
||||||
WHERE foreign_worker.worker_id = assignment.worker_id) LIMIT 100",
|
WHERE live_worker.worker_id = assignment.worker_id) LIMIT 100",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"ticket_current_worker_assignments.assignment_id",
|
"ticket_current_worker_assignments.assignment_id",
|
||||||
@@ -8501,6 +8503,12 @@ INSERT INTO ticket_worker_assignments (
|
|||||||
'workspace-b', 'ticket-b', 'assignment-cross-worker', 'runtime-a',
|
'workspace-b', 'ticket-b', 'assignment-cross-worker', 'runtime-a',
|
||||||
'00000000-0000-7000-8000-000000000001', 'tester', '2026-01-01'
|
'00000000-0000-7000-8000-000000000001', 'tester', '2026-01-01'
|
||||||
);
|
);
|
||||||
|
INSERT INTO ticket_worker_assignments (
|
||||||
|
workspace_id, ticket_id, assignment_id, runtime_id, worker_id, assigned_by, assigned_at
|
||||||
|
) VALUES (
|
||||||
|
'workspace-b', 'ticket-b', 'assignment-runtime-mismatch', 'runtime-wrong',
|
||||||
|
'00000000-0000-7000-8000-000000000002', 'tester', '2026-01-01'
|
||||||
|
);
|
||||||
INSERT INTO ticket_worker_assignments (
|
INSERT INTO ticket_worker_assignments (
|
||||||
workspace_id, ticket_id, assignment_id, runtime_id, worker_id, assigned_by, assigned_at
|
workspace_id, ticket_id, assignment_id, runtime_id, worker_id, assigned_by, assigned_at
|
||||||
) VALUES (
|
) VALUES (
|
||||||
@@ -8543,6 +8551,7 @@ INSERT INTO ticket_worker_assignment_events (
|
|||||||
"{error}"
|
"{error}"
|
||||||
);
|
);
|
||||||
assert!(error.contains("assignment-cross-worker"), "{error}");
|
assert!(error.contains("assignment-cross-worker"), "{error}");
|
||||||
|
assert!(error.contains("assignment-runtime-mismatch"), "{error}");
|
||||||
assert!(
|
assert!(
|
||||||
error.contains("ticket_worker_assignment_events.assignment_id"),
|
error.contains("ticket_worker_assignment_events.assignment_id"),
|
||||||
"{error}"
|
"{error}"
|
||||||
@@ -8597,6 +8606,14 @@ INSERT INTO ticket_worker_assignment_events (
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
assert!(cross_worker_assignment.is_err());
|
assert!(cross_worker_assignment.is_err());
|
||||||
|
let runtime_mismatch_assignment = conn.execute(
|
||||||
|
"INSERT INTO ticket_worker_assignments \
|
||||||
|
(workspace_id, ticket_id, assignment_id, runtime_id, worker_id, assigned_by, assigned_at) \
|
||||||
|
VALUES ('workspace-b', 'ticket-b', 'assignment-runtime-mismatch', 'runtime-wrong', \
|
||||||
|
'00000000-0000-7000-8000-000000000002', 'tester', '2026-01-01')",
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
assert!(runtime_mismatch_assignment.is_err());
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO ticket_worker_assignments \
|
"INSERT INTO ticket_worker_assignments \
|
||||||
(workspace_id, ticket_id, assignment_id, runtime_id, worker_id, assigned_by, assigned_at) \
|
(workspace_id, ticket_id, assignment_id, runtime_id, worker_id, assigned_by, assigned_at) \
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ Start exactly one instance of the new Server binary against the database. Startu
|
|||||||
|
|
||||||
- rebuilds Ticket, Objective, assignment, Artifact, and human-key tables with Workspace-scoped composite identity;
|
- rebuilds Ticket, Objective, assignment, Artifact, and human-key tables with Workspace-scoped composite identity;
|
||||||
- adds composite foreign keys for repository, Ticket, Objective, Worker, relation-target, and current-assignment references;
|
- adds composite foreign keys for repository, Ticket, Objective, Worker, relation-target, and current-assignment references;
|
||||||
- validates new historical assignment/event references with SQLite triggers while allowing those audit rows to survive later Ticket or Worker retention deletion; startup treats a parent missing from every Workspace as retained history but still rejects an id that resolves only in another Workspace; reservation operation ids remain intentionally unconstrained until their resources exist;
|
- validates new historical assignment/event references with SQLite triggers while allowing those audit rows to survive later Ticket or Worker retention deletion; startup treats a Ticket or Worker ID missing from every Workspace as retained history, but rejects a Ticket ID in another Workspace and rejects a live Worker ID whose Workspace/Runtime placement does not match the assignment snapshot; reservation operation ids remain intentionally unconstrained until their resources exist;
|
||||||
- checks the rebuilt schema with `PRAGMA foreign_key_check` before recording the schema version; and
|
- checks the rebuilt schema with `PRAGMA foreign_key_check` before recording the schema version; and
|
||||||
- restores `PRAGMA foreign_keys = ON` whether the transaction commits or rolls back.
|
- restores `PRAGMA foreign_keys = ON` whether the transaction commits or rolls back.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user