From 6762586e2dc5e9224fb377137dc8c18782556c30 Mon Sep 17 00:00:00 2001 From: Mia Wu Date: Tue, 16 Jun 2026 16:09:54 -0400 Subject: [PATCH] p3p implementation --- .gitignore | 1 + backend/app.py | 1 + backend/data/p3p_tests.csv | 78 +- backend/db.py | 30 +- backend/graph.py | 15 +- backend/output.txt | 2515 ------------------------------------ backend/parser.py | 181 ++- backend/scheduler.py | 1 + 8 files changed, 238 insertions(+), 2584 deletions(-) delete mode 100644 backend/output.txt diff --git a/.gitignore b/.gitignore index 2d700ec..ded0387 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /backend/.venv /backend/__pycache__ /backend/_run_sched_test.py +/backend/output.txt IMPLEMENTATIONPLAN.md scheduler.db scheduler.db* \ No newline at end of file diff --git a/backend/app.py b/backend/app.py index c5533f6..0583be4 100644 --- a/backend/app.py +++ b/backend/app.py @@ -121,6 +121,7 @@ def compile_schedule_endpoint(request: CompileScheduleRequest) -> dict[str, Any] has_coe_pair=t.has_coe_pair, coe_pairing=t.coe_pairing or [], config=t.config, + throttled=t.throttled, estimated_minutes=t.estimated_minutes, priority=t.priority, raw_payload=t.raw_payload or {}, diff --git a/backend/data/p3p_tests.csv b/backend/data/p3p_tests.csv index 1a296f0..614790a 100644 --- a/backend/data/p3p_tests.csv +++ b/backend/data/p3p_tests.csv @@ -1,71 +1,81 @@ Priority,Index,Throttled,Rotation,TC ID,Band,6GHz Power Mode,Station 1 Test Point,Station 1 Channel,Station 1 Bandwidth,Station 1 RSSI,Station 1 Direction,Station 1 Rate,Station 1 STA,Station 2 Test Point,Station 2 Channel,Station 2 Bandwidth,Station 2 RSSI,Station 2 Direction,Station 2 Rate,Station 2 STA,Station 3 Test Point,Station 3 Channel,Station 3 Bandwidth,Station 3 RSSI,Station 3 Direction,Station 3 Rate,Station 3 STA -P2,1,Yes,R3,P3PRXBETH001,5G,LPI,T1F,36,80,-76,UL,22Mbps,STA63,T1I,36,80,-76,UL,22Mbps,STA64,T2J,36,80,-76,UL,11Mbps,STA65 -P2,2,Yes,R3,P3PRXBETH002,5G,LPI,T1F,100,80,-76,UL,22Mbps,STA63,T1I,100,80,-76,UL,22Mbps,STA64,T2J,100,80,-76,UL,11Mbps,STA65 -P2,3,Yes,R3,P3PRXBETH003,5G,LPI,T1F,161,80,-76,UL,22Mbps,STA63,T1I,161,80,-76,UL,22Mbps,STA64,T2J,161,80,-76,UL,11Mbps,STA65 P2,4,Yes,R1,P3PRXBETH004,6G,LPI,T2A,5,160,-79,UL,22Mbps,STA63,T1L,5,160,-79,UL,22Mbps,STA64,T2O,5,160,-79,UL,11Mbps,STA65 P2,5,Yes,R1,P3PRXBETH005,6G,LPI,T2A,133,160,-79,UL,22Mbps,STA63,T1L,133,160,-79,UL,22Mbps,STA64,T2O,133,160,-79,UL,11Mbps,STA65 P2,6,Yes,R1,P3PRXBETH006,6G,LPI,T2A,197,160,-79,UL,22Mbps,STA63,T1L,197,160,-79,UL,22Mbps,STA64,T2O,197,160,-79,UL,11Mbps,STA65 -P2,7,Yes,R2,P3PRXBETH007,2G,LPI,T3E,6,20,-70,UL,22Mbps,STA63,T1P,6,20,-70,UL,22Mbps,STA64,T2Q,6,20,-70,UL,11Mbps,STA65 -P2,8,Yes,R1,P3PRXBETH008,6G,SP,T2A,5,320,-79,UL,22Mbps,STA63,T1L,5,320,-79,UL,22Mbps,STA64,T2O,5,320,-79,UL,11Mbps,STA65 P2,9,Yes,R1,P3PRXBETH009,6G,LPI,T2A,133,320,-79,UL,22Mbps,STA63,T1L,133,320,-79,UL,22Mbps,STA64,T2O,133,320,-79,UL,11Mbps,STA65 -P2,1,No,R3,P3PRXBEUT001,5G,LPI,T1F,36,80,-76,UL,Unlimited,STA63,T1I,36,80,-76,UL,Unlimited,STA64,T2J,36,80,-76,UL,Unlimited,STA65 -P2,2,No,R3,P3PRXBEUT002,5G,LPI,T1F,100,80,-76,UL,Unlimited,STA63,T1I,100,80,-76,UL,Unlimited,STA64,T2J,100,80,-76,UL,Unlimited,STA65 -P2,3,No,R3,P3PRXBEUT003,5G,LPI,T1F,161,80,-76,UL,Unlimited,STA63,T1I,161,80,-76,UL,Unlimited,STA64,T2J,161,80,-76,UL,Unlimited,STA65 P2,4,No,R1,P3PRXBEUT004,6G,LPI,T2A,5,160,-79,UL,Unlimited,STA63,T1L,5,160,-79,UL,Unlimited,STA64,T2O,5,160,-79,UL,Unlimited,STA65 P2,5,No,R1,P3PRXBEUT005,6G,LPI,T2A,133,160,-79,UL,Unlimited,STA63,T1L,133,160,-79,UL,Unlimited,STA64,T2O,133,160,-79,UL,Unlimited,STA65 P2,6,No,R1,P3PRXBEUT006,6G,LPI,T2A,197,160,-79,UL,Unlimited,STA63,T1L,197,160,-79,UL,Unlimited,STA64,T2O,197,160,-79,UL,Unlimited,STA65 -P2,7,No,R2,P3PRXBEUT007,2G,LPI,T3E,6,20,-70,UL,Unlimited,STA63,T1P,6,20,-70,UL,Unlimited,STA64,T2Q,6,20,-70,UL,Unlimited,STA65 -P2,8,No,R1,P3PRXBEUT008,6G,SP,T2A,5,320,-79,UL,Unlimited,STA63,T1L,5,320,-79,UL,Unlimited,STA64,T2O,5,320,-79,UL,Unlimited,STA65 P2,9,No,R1,P3PRXBEUT009,6G,LPI,T2A,133,320,-79,UL,Unlimited,STA63,T1L,133,320,-79,UL,Unlimited,STA64,T2O,133,320,-79,UL,Unlimited,STA65 +P2,4,Yes,R1,P3PTXBETH004,6G,LPI,T2A,5,160,-79,DL,22Mbps,STA63,T1L,5,160,-79,DL,22Mbps,STA64,T2O,5,160,-79,DL,11Mbps,STA65 +P2,5,Yes,R1,P3PTXBETH005,6G,LPI,T2A,133,160,-79,DL,22Mbps,STA63,T1L,133,160,-79,DL,22Mbps,STA64,T2O,133,160,-79,DL,11Mbps,STA65 +P2,6,Yes,R1,P3PTXBETH006,6G,LPI,T2A,197,160,-79,DL,22Mbps,STA63,T1L,197,160,-79,DL,22Mbps,STA64,T2O,197,160,-79,DL,11Mbps,STA65 +P2,9,Yes,R1,P3PTXBETH009,6G,LPI,T2A,133,320,-79,DL,22Mbps,STA63,T1L,133,320,-79,DL,22Mbps,STA64,T2O,133,320,-79,DL,11Mbps,STA65 +P2,4,No,R1,P3PTXBEUT004,6G,LPI,T2A,5,160,-79,DL,Unlimited,STA63,T1L,5,160,-79,DL,Unlimited,STA64,T2O,5,160,-79,DL,Unlimited,STA65 +P2,5,No,R1,P3PTXBEUT005,6G,LPI,T2A,133,160,-79,DL,Unlimited,STA63,T1L,133,160,-79,DL,Unlimited,STA64,T2O,133,160,-79,DL,Unlimited,STA65 +P2,6,No,R1,P3PTXBEUT006,6G,LPI,T2A,197,160,-79,DL,Unlimited,STA63,T1L,197,160,-79,DL,Unlimited,STA64,T2O,197,160,-79,DL,Unlimited,STA65 +P2,9,No,R1,P3PTXBEUT009,6G,LPI,T2A,133,320,-79,DL,Unlimited,STA63,T1L,133,320,-79,DL,Unlimited,STA64,T2O,133,320,-79,DL,Unlimited,STA65 P2,1,Yes,R1,P3PRXAXTH001,5G,LPI,T1F,36,80,-76,UL,22Mbps,STA56,T1I,36,80,-76,UL,22Mbps,STA58,T2J,36,80,-76,UL,11Mbps,STA59 P2,2,Yes,R1,P3PRXAXTH002,5G,LPI,T1F,100,80,-76,UL,22Mbps,STA56,T1I,100,80,-76,UL,22Mbps,STA58,T2J,100,80,-76,UL,11Mbps,STA59 P2,3,Yes,R1,P3PRXAXTH003,5G,LPI,T1F,161,80,-76,UL,22Mbps,STA56,T1I,161,80,-76,UL,22Mbps,STA58,T2J,161,80,-76,UL,11Mbps,STA59 -P2,4,Yes,R2,P3PRXAXTH004,6G,LPI,T2A,5,160,-79,UL,22Mbps,STA56,T1L,5,160,-79,UL,22Mbps,STA58,T2O,5,160,-79,UL,11Mbps,STA59 -P2,5,Yes,R2,P3PRXAXTH005,6G,LPI,T2A,133,160,-79,UL,22Mbps,STA56,T1L,133,160,-79,UL,22Mbps,STA58,T2O,133,160,-79,UL,11Mbps,STA59 -P2,6,Yes,R2,P3PRXAXTH006,6G,LPI,T2A,197,160,-79,UL,22Mbps,STA56,T1L,197,160,-79,UL,22Mbps,STA58,T2O,197,160,-79,UL,11Mbps,STA59 -P2,7,Yes,R3,P3PRXAXTH007,2G,LPI,T3E,6,20,-70,UL,22Mbps,STA56,T1P,6,20,-70,UL,22Mbps,STA58,T2Q,6,20,-70,UL,11Mbps,STA59 -P2,8,Yes,R2,P3PRXAXTH008,6G,SP,T2A,5,320,-79,UL,22Mbps,STA56,T1L,5,320,-79,UL,22Mbps,STA58,T2O,5,320,-79,UL,11Mbps,STA59 -P2,9,Yes,R2,P3PRXAXTH009,6G,LPI,T2A,133,320,-79,UL,22Mbps,STA56,T1L,133,320,-79,UL,22Mbps,STA58,T2O,133,320,-79,UL,11Mbps,STA59 P2,1,No,R1,P3PRXAXUT001,5G,LPI,T1F,36,80,-76,UL,Unlimited,STA56,T1I,36,80,-76,UL,Unlimited,STA58,T2J,36,80,-76,UL,Unlimited,STA59 P2,2,No,R1,P3PRXAXUT002,5G,LPI,T1F,100,80,-76,UL,Unlimited,STA56,T1I,100,80,-76,UL,Unlimited,STA58,T2J,100,80,-76,UL,Unlimited,STA59 P2,3,No,R1,P3PRXAXUT003,5G,LPI,T1F,161,80,-76,UL,Unlimited,STA56,T1I,161,80,-76,UL,Unlimited,STA58,T2J,161,80,-76,UL,Unlimited,STA59 -P2,4,No,R2,P3PRXAXUT004,6G,LPI,T2A,5,160,-79,UL,Unlimited,STA56,T1L,5,160,-79,UL,Unlimited,STA58,T2O,5,160,-79,UL,Unlimited,STA59 -P2,5,No,R2,P3PRXAXUT005,6G,LPI,T2A,133,160,-79,UL,Unlimited,STA56,T1L,133,160,-79,UL,Unlimited,STA58,T2O,133,160,-79,UL,Unlimited,STA59 -P2,6,No,R2,P3PRXAXUT006,6G,LPI,T2A,197,160,-79,UL,Unlimited,STA56,T1L,197,160,-79,UL,Unlimited,STA58,T2O,197,160,-79,UL,Unlimited,STA59 -P2,7,No,R3,P3PRXAXUT007,2G,LPI,T3E,6,20,-70,UL,Unlimited,STA56,T1P,6,20,-70,UL,Unlimited,STA58,T2Q,6,20,-70,UL,Unlimited,STA59 -P2,8,No,R2,P3PRXAXUT008,6G,SP,T2A,5,320,-79,UL,Unlimited,STA56,T1L,5,320,-79,UL,Unlimited,STA58,T2O,5,320,-79,UL,Unlimited,STA59 -P2,9,No,R2,P3PRXAXUT009,6G,LPI,T2A,133,320,-79,UL,Unlimited,STA56,T1L,133,320,-79,UL,Unlimited,STA58,T2O,133,320,-79,UL,Unlimited,STA59 P2,1,Yes,R1,P3PTXAXTH001,5G,LPI,T1F,36,80,-76,DL,22Mbps,STA56,T1I,36,80,-76,DL,22Mbps,STA58,T2J,36,80,-76,DL,11Mbps,STA59 P2,2,Yes,R1,P3PTXAXTH002,5G,LPI,T1F,100,80,-76,DL,22Mbps,STA56,T1I,100,80,-76,DL,22Mbps,STA58,T2J,100,80,-76,DL,11Mbps,STA59 P2,3,Yes,R1,P3PTXAXTH003,5G,LPI,T1F,161,80,-76,DL,22Mbps,STA56,T1I,161,80,-76,DL,22Mbps,STA58,T2J,161,80,-76,DL,11Mbps,STA59 -P2,4,Yes,R2,P3PTXAXTH004,6G,LPI,T2A,5,160,-79,DL,22Mbps,STA56,T1L,5,160,-79,DL,22Mbps,STA58,T2O,5,160,-79,DL,11Mbps,STA59 -P2,5,Yes,R2,P3PTXAXTH005,6G,LPI,T2A,133,160,-79,DL,22Mbps,STA56,T1L,133,160,-79,DL,22Mbps,STA58,T2O,133,160,-79,DL,11Mbps,STA59 -P2,6,Yes,R2,P3PTXAXTH006,6G,LPI,T2A,197,160,-79,DL,22Mbps,STA56,T1L,197,160,-79,DL,22Mbps,STA58,T2O,197,160,-79,DL,11Mbps,STA59 -P2,7,Yes,R3,P3PTXAXTH007,2G,LPI,T3E,6,20,-70,DL,22Mbps,STA56,T1P,6,20,-70,DL,22Mbps,STA58,T2Q,6,20,-70,DL,11Mbps,STA59 -P2,8,Yes,R2,P3PTXAXTH008,6G,SP,T2A,5,320,-79,DL,22Mbps,STA56,T1L,5,320,-79,DL,22Mbps,STA58,T2O,5,320,-79,DL,11Mbps,STA59 -P2,9,Yes,R2,P3PTXAXTH009,6G,LPI,T2A,133,320,-79,DL,22Mbps,STA56,T1L,133,320,-79,DL,22Mbps,STA58,T2O,133,320,-79,DL,11Mbps,STA59 P2,1,No,R1,P3PTXAXUT001,5G,LPI,T1F,36,80,-76,DL,Unlimited,STA56,T1I,36,80,-76,DL,Unlimited,STA58,T2J,36,80,-76,DL,Unlimited,STA59 P2,2,No,R1,P3PTXAXUT002,5G,LPI,T1F,100,80,-76,DL,Unlimited,STA56,T1I,100,80,-76,DL,Unlimited,STA58,T2J,100,80,-76,DL,Unlimited,STA59 P2,3,No,R1,P3PTXAXUT003,5G,LPI,T1F,161,80,-76,DL,Unlimited,STA56,T1I,161,80,-76,DL,Unlimited,STA58,T2J,161,80,-76,DL,Unlimited,STA59 +P2,4,Yes,R1,P3PRXACTH004,2G,LPI,T3E,6,20,-70,UL,22Mbps,STA4,T1P,6,20,-70,UL,22Mbps,STA5,T2Q,6,20,-70,UL,11Mbps,STA6 +P2,4,No,R1,P3PRXACUT004,2G,LPI,T3E,6,20,-70,UL,Unlimited,STA4,T1P,6,20,-70,UL,Unlimited,STA5,T2Q,6,20,-70,UL,Unlimited,STA6 +P2,4,Yes,R1,P3PTXACTH004,2G,LPI,T3E,6,20,-70,DL,22Mbps,STA4,T1P,6,20,-70,DL,22Mbps,STA5,T2Q,6,20,-70,DL,11Mbps,STA6 +P2,4,No,R1,P3PTXACUT004,2G,LPI,T3E,6,20,-70,DL,Unlimited,STA4,T1P,6,20,-70,DL,Unlimited,STA5,T2Q,6,20,-70,DL,Unlimited,STA6 +P2,7,Yes,R2,P3PRXBETH007,2G,LPI,T3E,6,20,-70,UL,22Mbps,STA63,T1P,6,20,-70,UL,22Mbps,STA64,T2Q,6,20,-70,UL,11Mbps,STA65 +P2,7,No,R2,P3PRXBEUT007,2G,LPI,T3E,6,20,-70,UL,Unlimited,STA63,T1P,6,20,-70,UL,Unlimited,STA64,T2Q,6,20,-70,UL,Unlimited,STA65 +P2,7,Yes,R2,P3PTXBETH007,2G,LPI,T3E,6,20,-70,DL,22Mbps,STA63,T1P,6,20,-70,DL,22Mbps,STA64,T2Q,6,20,-70,DL,11Mbps,STA65 +P2,7,No,R2,P3PTXBEUT007,2G,LPI,T3E,6,20,-70,DL,Unlimited,STA63,T1P,6,20,-70,DL,Unlimited,STA64,T2Q,6,20,-70,DL,Unlimited,STA65 +P2,4,Yes,R2,P3PRXAXTH004,6G,LPI,T2A,5,160,-79,UL,22Mbps,STA56,T1L,5,160,-79,UL,22Mbps,STA58,T2O,5,160,-79,UL,11Mbps,STA59 +P2,5,Yes,R2,P3PRXAXTH005,6G,LPI,T2A,133,160,-79,UL,22Mbps,STA56,T1L,133,160,-79,UL,22Mbps,STA58,T2O,133,160,-79,UL,11Mbps,STA59 +P2,6,Yes,R2,P3PRXAXTH006,6G,LPI,T2A,197,160,-79,UL,22Mbps,STA56,T1L,197,160,-79,UL,22Mbps,STA58,T2O,197,160,-79,UL,11Mbps,STA59 +P2,9,Yes,R2,P3PRXAXTH009,6G,LPI,T2A,133,320,-79,UL,22Mbps,STA56,T1L,133,320,-79,UL,22Mbps,STA58,T2O,133,320,-79,UL,11Mbps,STA59 +P2,4,No,R2,P3PRXAXUT004,6G,LPI,T2A,5,160,-79,UL,Unlimited,STA56,T1L,5,160,-79,UL,Unlimited,STA58,T2O,5,160,-79,UL,Unlimited,STA59 +P2,5,No,R2,P3PRXAXUT005,6G,LPI,T2A,133,160,-79,UL,Unlimited,STA56,T1L,133,160,-79,UL,Unlimited,STA58,T2O,133,160,-79,UL,Unlimited,STA59 +P2,6,No,R2,P3PRXAXUT006,6G,LPI,T2A,197,160,-79,UL,Unlimited,STA56,T1L,197,160,-79,UL,Unlimited,STA58,T2O,197,160,-79,UL,Unlimited,STA59 +P2,9,No,R2,P3PRXAXUT009,6G,LPI,T2A,133,320,-79,UL,Unlimited,STA56,T1L,133,320,-79,UL,Unlimited,STA58,T2O,133,320,-79,UL,Unlimited,STA59 +P2,4,Yes,R2,P3PTXAXTH004,6G,LPI,T2A,5,160,-79,DL,22Mbps,STA56,T1L,5,160,-79,DL,22Mbps,STA58,T2O,5,160,-79,DL,11Mbps,STA59 +P2,5,Yes,R2,P3PTXAXTH005,6G,LPI,T2A,133,160,-79,DL,22Mbps,STA56,T1L,133,160,-79,DL,22Mbps,STA58,T2O,133,160,-79,DL,11Mbps,STA59 +P2,6,Yes,R2,P3PTXAXTH006,6G,LPI,T2A,197,160,-79,DL,22Mbps,STA56,T1L,197,160,-79,DL,22Mbps,STA58,T2O,197,160,-79,DL,11Mbps,STA59 +P2,9,Yes,R2,P3PTXAXTH009,6G,LPI,T2A,133,320,-79,DL,22Mbps,STA56,T1L,133,320,-79,DL,22Mbps,STA58,T2O,133,320,-79,DL,11Mbps,STA59 P2,4,No,R2,P3PTXAXUT004,6G,LPI,T2A,5,160,-79,DL,Unlimited,STA56,T1L,5,160,-79,DL,Unlimited,STA58,T2O,5,160,-79,DL,Unlimited,STA59 P2,5,No,R2,P3PTXAXUT005,6G,LPI,T2A,133,160,-79,DL,Unlimited,STA56,T1L,133,160,-79,DL,Unlimited,STA58,T2O,133,160,-79,DL,Unlimited,STA59 P2,6,No,R2,P3PTXAXUT006,6G,LPI,T2A,197,160,-79,DL,Unlimited,STA56,T1L,197,160,-79,DL,Unlimited,STA58,T2O,197,160,-79,DL,Unlimited,STA59 -P2,7,No,R3,P3PTXAXUT007,2G,LPI,T3E,6,20,-70,DL,Unlimited,STA56,T1P,6,20,-70,DL,Unlimited,STA58,T2Q,6,20,-70,DL,Unlimited,STA59 -P2,8,No,R2,P3PTXAXUT008,6G,SP,T2A,5,320,-79,DL,Unlimited,STA56,T1L,5,320,-79,DL,Unlimited,STA58,T2O,5,320,-79,DL,Unlimited,STA59 P2,9,No,R2,P3PTXAXUT009,6G,LPI,T2A,133,320,-79,DL,Unlimited,STA56,T1L,133,320,-79,DL,Unlimited,STA58,T2O,133,320,-79,DL,Unlimited,STA59 P2,1,Yes,R2,P3PRXACTH001,5G,LPI,T1F,36,80,-76,UL,22Mbps,STA4,T1I,36,80,-76,UL,22Mbps,STA5,T2J,36,80,-76,UL,11Mbps,STA6 P2,2,Yes,R2,P3PRXACTH002,5G,LPI,T1F,100,80,-76,UL,22Mbps,STA4,T1I,100,80,-76,UL,22Mbps,STA5,T2J,100,80,-76,UL,11Mbps,STA6 P2,3,Yes,R2,P3PRXACTH003,5G,LPI,T1F,161,80,-76,UL,22Mbps,STA4,T1I,161,80,-76,UL,22Mbps,STA5,T2J,161,80,-76,UL,11Mbps,STA6 -P2,4,Yes,R1,P3PRXACTH004,2G,LPI,T3E,6,20,-70,UL,22Mbps,STA4,T1P,6,20,-70,UL,22Mbps,STA5,T2Q,6,20,-70,UL,11Mbps,STA6 P2,1,No,R2,P3PRXACUT001,5G,LPI,T1F,36,80,-76,UL,Unlimited,STA4,T1I,36,80,-76,UL,Unlimited,STA5,T2J,36,80,-76,UL,Unlimited,STA6 P2,2,No,R2,P3PRXACUT002,5G,LPI,T1F,100,80,-76,UL,Unlimited,STA4,T1I,100,80,-76,UL,Unlimited,STA5,T2J,100,80,-76,UL,Unlimited,STA6 P2,3,No,R2,P3PRXACUT003,5G,LPI,T1F,161,80,-76,UL,Unlimited,STA4,T1I,161,80,-76,UL,Unlimited,STA5,T2J,161,80,-76,UL,Unlimited,STA6 -P2,4,No,R1,P3PRXACUT004,2G,LPI,T3E,6,20,-70,UL,Unlimited,STA4,T1P,6,20,-70,UL,Unlimited,STA5,T2Q,6,20,-70,UL,Unlimited,STA6 P2,1,Yes,R2,P3PTXACTH001,5G,LPI,T1F,36,80,-76,DL,22Mbps,STA4,T1I,36,80,-76,DL,22Mbps,STA5,T2J,36,80,-76,DL,11Mbps,STA6 P2,2,Yes,R2,P3PTXACTH002,5G,LPI,T1F,100,80,-76,DL,22Mbps,STA4,T1I,100,80,-76,DL,22Mbps,STA5,T2J,100,80,-76,DL,11Mbps,STA6 P2,3,Yes,R2,P3PTXACTH003,5G,LPI,T1F,161,80,-76,DL,22Mbps,STA4,T1I,161,80,-76,DL,22Mbps,STA5,T2J,161,80,-76,DL,11Mbps,STA6 -P2,4,Yes,R1,P3PTXACTH004,2G,LPI,T3E,6,20,-70,DL,22Mbps,STA4,T1P,6,20,-70,DL,22Mbps,STA5,T2Q,6,20,-70,DL,11Mbps,STA6 P2,1,No,R2,P3PTXACUT001,5G,LPI,T1F,36,80,-76,DL,Unlimited,STA4,T1I,36,80,-76,DL,Unlimited,STA5,T2J,36,80,-76,DL,Unlimited,STA6 P2,2,No,R2,P3PTXACUT002,5G,LPI,T1F,100,80,-76,DL,Unlimited,STA4,T1I,100,80,-76,DL,Unlimited,STA5,T2J,100,80,-76,DL,Unlimited,STA6 P2,3,No,R2,P3PTXACUT003,5G,LPI,T1F,161,80,-76,DL,Unlimited,STA4,T1I,161,80,-76,DL,Unlimited,STA5,T2J,161,80,-76,DL,Unlimited,STA6 -P2,4,No,R1,P3PTXACUT004,2G,LPI,T3E,6,20,-70,DL,Unlimited,STA4,T1P,6,20,-70,DL,Unlimited,STA5,T2Q,6,20,-70,DL,Unlimited,STA6 +P2,1,Yes,R3,P3PRXBETH001,5G,LPI,T1F,36,80,-76,UL,22Mbps,STA63,T1I,36,80,-76,UL,22Mbps,STA64,T2J,36,80,-76,UL,11Mbps,STA65 +P2,2,Yes,R3,P3PRXBETH002,5G,LPI,T1F,100,80,-76,UL,22Mbps,STA63,T1I,100,80,-76,UL,22Mbps,STA64,T2J,100,80,-76,UL,11Mbps,STA65 +P2,3,Yes,R3,P3PRXBETH003,5G,LPI,T1F,161,80,-76,UL,22Mbps,STA63,T1I,161,80,-76,UL,22Mbps,STA64,T2J,161,80,-76,UL,11Mbps,STA65 +P2,1,No,R3,P3PRXBEUT001,5G,LPI,T1F,36,80,-76,UL,Unlimited,STA63,T1I,36,80,-76,UL,Unlimited,STA64,T2J,36,80,-76,UL,Unlimited,STA65 +P2,2,No,R3,P3PRXBEUT002,5G,LPI,T1F,100,80,-76,UL,Unlimited,STA63,T1I,100,80,-76,UL,Unlimited,STA64,T2J,100,80,-76,UL,Unlimited,STA65 +P2,3,No,R3,P3PRXBEUT003,5G,LPI,T1F,161,80,-76,UL,Unlimited,STA63,T1I,161,80,-76,UL,Unlimited,STA64,T2J,161,80,-76,UL,Unlimited,STA65 +P2,1,Yes,R3,P3PTXBETH001,5G,LPI,T1F,36,80,-76,DL,22Mbps,STA63,T1I,36,80,-76,DL,22Mbps,STA64,T2J,36,80,-76,DL,11Mbps,STA65 +P2,2,Yes,R3,P3PTXBETH002,5G,LPI,T1F,100,80,-76,DL,22Mbps,STA63,T1I,100,80,-76,DL,22Mbps,STA64,T2J,100,80,-76,DL,11Mbps,STA65 +P2,3,Yes,R3,P3PTXBETH003,5G,LPI,T1F,161,80,-76,DL,22Mbps,STA63,T1I,161,80,-76,DL,22Mbps,STA64,T2J,161,80,-76,DL,11Mbps,STA65 +P2,1,No,R3,P3PTXBEUT001,5G,LPI,T1F,36,80,-76,DL,Unlimited,STA63,T1I,36,80,-76,DL,Unlimited,STA64,T2J,36,80,-76,DL,Unlimited,STA65 +P2,2,No,R3,P3PTXBEUT002,5G,LPI,T1F,100,80,-76,DL,Unlimited,STA63,T1I,100,80,-76,DL,Unlimited,STA64,T2J,100,80,-76,DL,Unlimited,STA65 +P2,3,No,R3,P3PTXBEUT003,5G,LPI,T1F,161,80,-76,DL,Unlimited,STA63,T1I,161,80,-76,DL,Unlimited,STA64,T2J,161,80,-76,DL,Unlimited,STA65 +P2,7,Yes,R3,P3PRXAXTH007,2G,LPI,T1D,6,20,-70,UL,22Mbps,STA56,T1P,6,20,-70,UL,22Mbps,STA58,T2Q,6,20,-70,UL,11Mbps,STA59 +P2,7,No,R3,P3PRXAXUT007,2G,LPI,T1D,6,20,-70,UL,Unlimited,STA56,T1P,6,20,-70,UL,Unlimited,STA58,T2Q,6,20,-70,UL,Unlimited,STA59 +P2,7,Yes,R3,P3PTXAXTH007,2G,LPI,T1D,6,20,-70,DL,22Mbps,STA56,T1P,6,20,-70,DL,22Mbps,STA58,T2Q,6,20,-70,DL,11Mbps,STA59 +P2,7,No,R3,P3PTXAXUT007,2G,LPI,T1D,6,20,-70,DL,Unlimited,STA56,T1P,6,20,-70,DL,Unlimited,STA58,T2Q,6,20,-70,DL,Unlimited,STA59 diff --git a/backend/db.py b/backend/db.py index ffb01cb..b9259f3 100644 --- a/backend/db.py +++ b/backend/db.py @@ -31,6 +31,7 @@ class TestRecord: priority: int victim_band: str | None config: dict[str, dict[str, str | None]] + throttled: bool estimated_minutes: int status: str = "pending" excluded: bool = False @@ -81,6 +82,7 @@ def init_db(db_path: str | Path = DB_PATH) -> None: priority INTEGER NOT NULL CHECK (priority BETWEEN 1 AND 5), victim_band TEXT, config_json TEXT, + throttled INTEGER NOT NULL DEFAULT 0, estimated_minutes INTEGER NOT NULL, status TEXT NOT NULL CHECK (status IN ('pending', 'completed', 'failed', 'invalid')), excluded INTEGER NOT NULL DEFAULT 0, @@ -137,6 +139,7 @@ def init_db(db_path: str | Path = DB_PATH) -> None: _ensure_column(conn, "tests", "config_json", "TEXT") _ensure_column(conn, "tests", "victim_band", "TEXT") _ensure_column(conn, "tests", "excluded", "INTEGER NOT NULL DEFAULT 0") + _ensure_column(conn, "tests", "throttled", "INTEGER NOT NULL DEFAULT 0") # Seed runtime defaults for schedule estimation. conn.execute( @@ -159,9 +162,9 @@ def upsert_tests(records: list[TestRecord], db_path: str | Path = DB_PATH) -> in """ INSERT INTO tests( test_id, device, test_type, rotation, rx_tx, has_coe_pair, - coe_pairing_json, config_json, priority, victim_band, estimated_minutes, status, excluded, raw_payload + coe_pairing_json, config_json, priority, victim_band, throttled, estimated_minutes, status, excluded, raw_payload ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(test_id, device) DO UPDATE SET test_type = excluded.test_type, device = excluded.device, @@ -172,6 +175,7 @@ def upsert_tests(records: list[TestRecord], db_path: str | Path = DB_PATH) -> in config_json = excluded.config_json, priority = excluded.priority, victim_band = excluded.victim_band, + throttled = excluded.throttled, estimated_minutes = excluded.estimated_minutes, status = excluded.status, excluded = excluded.excluded, @@ -190,6 +194,7 @@ def upsert_tests(records: list[TestRecord], db_path: str | Path = DB_PATH) -> in json.dumps(r.config), r.priority, r.victim_band, + int(r.throttled), r.estimated_minutes, r.status, int(r.excluded), @@ -260,13 +265,24 @@ def _entry_value(entry: dict[str, str | None], key: str) -> str: return _normalize_text(entry.get(key) or entry.get(key.capitalize()) or entry.get(key.upper())) +def _record_power_mode(record: TestRecord) -> str: + power_mode = _entry_value(_band_entry(record.config, "6G"), "power_mode") + if power_mode: + return power_mode + + raw_payload = record.raw_payload or {} + return _normalize_text(raw_payload.get("6GHz Power Mode")) + + def _match_any_band_value(record: TestRecord, key: str, token_suffix: str) -> bool: if not token_suffix: return False target_num = _extract_signed_int(token_suffix) target_compact = _normalize_compact(token_suffix) - for band in ("5G", "6G", "2G"): + keys = ("Station 1", "Station 2", "Station 3") if record.test_type == "P3P" else ("5G", "6G", "2G") + + for band in keys: entry = _band_entry(record.config, band) value = _entry_value(entry, key) if not value: @@ -289,7 +305,7 @@ def _matches_atomic_exclusion_token(record: TestRecord, token: str) -> bool: test_type = _normalize_text(record.test_type) rotation = _normalize_text(record.rotation) victim_band = _normalize_text(record.victim_band) - power_mode = _entry_value(_band_entry(record.config, "6G"), "power_mode") + power_mode = _record_power_mode(record) known_devices = {_normalize_text(DUT), _normalize_text(REF)} if token in {"LPI", "SP"}: @@ -343,7 +359,7 @@ def list_schedulable_tests(db_path: str | Path = DB_PATH, rule: str = "") -> lis SELECT test_id, device, test_type, rotation, rx_tx, has_coe_pair, config_json, victim_band, - coe_pairing_json, priority, estimated_minutes, + coe_pairing_json, priority, throttled, estimated_minutes, excluded, status, raw_payload FROM tests WHERE excluded = 0 @@ -365,6 +381,7 @@ def list_schedulable_tests(db_path: str | Path = DB_PATH, rule: str = "") -> lis priority=int(row["priority"]), victim_band=row["victim_band"], config=json.loads(row["config_json"] or "{}"), + throttled=bool(row["throttled"]), estimated_minutes=int(row["estimated_minutes"]), status=row["status"], excluded=bool(row["excluded"]), @@ -384,7 +401,7 @@ def list_tests_for_device(device: str, db_path: str | Path = DB_PATH) -> list[Te SELECT test_id, device, test_type, rotation, rx_tx, has_coe_pair, config_json, victim_band, - coe_pairing_json, priority, estimated_minutes, + coe_pairing_json, priority, throttled, estimated_minutes, excluded, status, raw_payload FROM tests WHERE device = ? @@ -406,6 +423,7 @@ def list_tests_for_device(device: str, db_path: str | Path = DB_PATH) -> list[Te priority=int(row["priority"]), victim_band=row["victim_band"], config=json.loads(row["config_json"] or "{}"), + throttled=bool(row["throttled"]), estimated_minutes=int(row["estimated_minutes"]), status=row["status"], excluded=bool(row["excluded"]), diff --git a/backend/graph.py b/backend/graph.py index c444419..8442370 100644 --- a/backend/graph.py +++ b/backend/graph.py @@ -73,16 +73,25 @@ def _same_test_points_for_overlap( def _build_station_testpoint_map(config: dict[str, dict[str, str | None]]) -> dict[str, str]: station_to_testpoint: dict[str, str] = {} - for band in ("5G", "6G", "2G"): - entry = config.get(band) or {} + + def _add_entry(entry: dict[str, str | None]) -> None: testpoint = _norm(entry.get("test_point") or entry.get("Testpoint")) sta_raw = _norm(entry.get("sta") or entry.get("STA")) if not testpoint or not sta_raw: - continue + return for sta in sta_raw.split(","): sta_clean = _norm(sta) if sta_clean: station_to_testpoint[sta_clean] = testpoint + + for band in ("5G", "6G", "2G"): + entry = config.get(band) or {} + _add_entry(entry) + + for station_key in ("Station 1", "Station 2", "Station 3"): + entry = config.get(station_key) or {} + _add_entry(entry) + return station_to_testpoint diff --git a/backend/output.txt b/backend/output.txt deleted file mode 100644 index 543f3c0..0000000 --- a/backend/output.txt +++ /dev/null @@ -1,2515 +0,0 @@ -INPUT: data/p2p_coe_tests.csv -EXCLUSION_RULE: sp, bw320, cgw452_coe, cgw452_p3p, p3p_r2, p3p_r3 -DUT_RESULTS_DIR: C:\Users\26005101\Desktop\MIA\Test_results\DUT -REF_RESULTS_DIR: C:\Users\26005101\Desktop\MIA\Test_results\REF -PARSED_TESTS: 500\nCOMPLETED_TEST_IDS: ['COERXAX014:CGW453', 'P2PRXAC010:CGW452', 'P2PRXAX012:CGW452'] -REMAINING_SCHEDULABLE_TESTS: 358 -SCHEDULED_COMPLETED_IDS: [] -WARNINGS: 0\n\n\nSCHEDULE:\n[ - { - "test_id": "P2PRXAX010", - "device": "CGW453", - "scheduled_date": "2026-06-16", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAX010", - "device": "CGW452", - "scheduled_date": "2026-06-16", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXBE010", - "device": "CGW453", - "scheduled_date": "2026-06-16", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE010", - "device": "CGW452", - "scheduled_date": "2026-06-16", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAC016", - "device": "CGW453", - "scheduled_date": "2026-06-16", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAC016", - "device": "CGW452", - "scheduled_date": "2026-06-17", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAX010", - "device": "CGW453", - "scheduled_date": "2026-06-17", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX010", - "device": "CGW452", - "scheduled_date": "2026-06-17", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXBE010", - "device": "CGW453", - "scheduled_date": "2026-06-17", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE010", - "device": "CGW452", - "scheduled_date": "2026-06-17", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAX012", - "device": "CGW452", - "scheduled_date": "2026-06-17", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PRXAX028", - "device": "CGW453", - "scheduled_date": "2026-06-17", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAX028", - "device": "CGW452", - "scheduled_date": "2026-06-17", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAC004", - "device": "CGW453", - "scheduled_date": "2026-06-17", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "COERXAC001", - "device": "CGW453", - "scheduled_date": "2026-06-17", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAC004", - "device": "CGW452", - "scheduled_date": "2026-06-18", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAC007", - "device": "CGW453", - "scheduled_date": "2026-06-18", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "COERXAC002", - "device": "CGW453", - "scheduled_date": "2026-06-18", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAC007", - "device": "CGW452", - "scheduled_date": "2026-06-18", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAX031", - "device": "CGW453", - "scheduled_date": "2026-06-18", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "COERXAX015", - "device": "CGW453", - "scheduled_date": "2026-06-18", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PRXAX031", - "device": "CGW452", - "scheduled_date": "2026-06-18", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXAC010", - "device": "CGW453", - "scheduled_date": "2026-06-18", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COERXAC003", - "device": "CGW453", - "scheduled_date": "2026-06-18", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAC013", - "device": "CGW453", - "scheduled_date": "2026-06-18", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "COERXAC004", - "device": "CGW453", - "scheduled_date": "2026-06-18", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAC013", - "device": "CGW452", - "scheduled_date": "2026-06-19", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAC016", - "device": "CGW453", - "scheduled_date": "2026-06-19", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "COERXAC005", - "device": "CGW453", - "scheduled_date": "2026-06-19", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAC016", - "device": "CGW452", - "scheduled_date": "2026-06-19", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXBE013", - "device": "CGW453", - "scheduled_date": "2026-06-19", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "COERXBE009", - "device": "CGW453", - "scheduled_date": "2026-06-19", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PRXBE013", - "device": "CGW452", - "scheduled_date": "2026-06-19", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXAX013", - "device": "CGW453", - "scheduled_date": "2026-06-19", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COERXAX009", - "device": "CGW453", - "scheduled_date": "2026-06-19", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX013", - "device": "CGW452", - "scheduled_date": "2026-06-19", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAX016", - "device": "CGW453", - "scheduled_date": "2026-06-19", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "COERXAX010", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAX016", - "device": "CGW452", - "scheduled_date": "2026-06-20", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX019", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "COERXAX011", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAX019", - "device": "CGW452", - "scheduled_date": "2026-06-20", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE028", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 2, - "sequence_in_shift": 1 - }, - { - "test_id": "COERXBE014", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 2, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXBE028", - "device": "CGW452", - "scheduled_date": "2026-06-20", - "shift_index": 2, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE031", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 2, - "sequence_in_shift": 4 - }, - { - "test_id": "COERXBE015", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 2, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE031", - "device": "CGW452", - "scheduled_date": "2026-06-20", - "shift_index": 2, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PRXBE034", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COERXBE016", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXBE034", - "device": "CGW452", - "scheduled_date": "2026-06-20", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAC004", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "COETXAC001", - "device": "CGW453", - "scheduled_date": "2026-06-20", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAC004", - "device": "CGW452", - "scheduled_date": "2026-06-21", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAC007", - "device": "CGW453", - "scheduled_date": "2026-06-21", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "COETXAC002", - "device": "CGW453", - "scheduled_date": "2026-06-21", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAC007", - "device": "CGW452", - "scheduled_date": "2026-06-21", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX013", - "device": "CGW453", - "scheduled_date": "2026-06-21", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "COETXAX007", - "device": "CGW453", - "scheduled_date": "2026-06-21", - "shift_index": 2, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAX013", - "device": "CGW452", - "scheduled_date": "2026-06-21", - "shift_index": 2, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX016", - "device": "CGW453", - "scheduled_date": "2026-06-21", - "shift_index": 2, - "sequence_in_shift": 3 - }, - { - "test_id": "COETXAX008", - "device": "CGW453", - "scheduled_date": "2026-06-21", - "shift_index": 2, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX016", - "device": "CGW452", - "scheduled_date": "2026-06-21", - "shift_index": 2, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAX019", - "device": "CGW453", - "scheduled_date": "2026-06-21", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COETXAX009", - "device": "CGW453", - "scheduled_date": "2026-06-21", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX019", - "device": "CGW452", - "scheduled_date": "2026-06-21", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXBE028", - "device": "CGW453", - "scheduled_date": "2026-06-21", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE028", - "device": "CGW452", - "scheduled_date": "2026-06-21", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXBE031", - "device": "CGW453", - "scheduled_date": "2026-06-21", - "shift_index": 3, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE031", - "device": "CGW452", - "scheduled_date": "2026-06-22", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXBE034", - "device": "CGW453", - "scheduled_date": "2026-06-22", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE034", - "device": "CGW452", - "scheduled_date": "2026-06-22", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAC001", - "device": "CGW453", - "scheduled_date": "2026-06-22", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAC001", - "device": "CGW453", - "scheduled_date": "2026-06-22", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAC001", - "device": "CGW452", - "scheduled_date": "2026-06-22", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAC001", - "device": "CGW452", - "scheduled_date": "2026-06-22", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXAX034", - "device": "CGW453", - "scheduled_date": "2026-06-22", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COERXAX016", - "device": "CGW453", - "scheduled_date": "2026-06-22", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX034", - "device": "CGW452", - "scheduled_date": "2026-06-22", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAX028", - "device": "CGW453", - "scheduled_date": "2026-06-22", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "COETXAX012", - "device": "CGW453", - "scheduled_date": "2026-06-23", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAX028", - "device": "CGW452", - "scheduled_date": "2026-06-23", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX031", - "device": "CGW453", - "scheduled_date": "2026-06-23", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "COETXAX013", - "device": "CGW453", - "scheduled_date": "2026-06-23", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX031", - "device": "CGW452", - "scheduled_date": "2026-06-23", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXBE013", - "device": "CGW453", - "scheduled_date": "2026-06-23", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE013", - "device": "CGW452", - "scheduled_date": "2026-06-23", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXBE016", - "device": "CGW453", - "scheduled_date": "2026-06-23", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COERXBE010", - "device": "CGW453", - "scheduled_date": "2026-06-23", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXBE016", - "device": "CGW452", - "scheduled_date": "2026-06-23", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE019", - "device": "CGW453", - "scheduled_date": "2026-06-23", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "COERXBE011", - "device": "CGW453", - "scheduled_date": "2026-06-24", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE019", - "device": "CGW452", - "scheduled_date": "2026-06-24", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAC010", - "device": "CGW453", - "scheduled_date": "2026-06-24", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "COETXAC003", - "device": "CGW453", - "scheduled_date": "2026-06-24", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAC010", - "device": "CGW452", - "scheduled_date": "2026-06-24", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAX012", - "device": "CGW453", - "scheduled_date": "2026-06-24", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAX012", - "device": "CGW453", - "scheduled_date": "2026-06-24", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PTXAC013", - "device": "CGW453", - "scheduled_date": "2026-06-24", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COETXAC004", - "device": "CGW453", - "scheduled_date": "2026-06-24", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAC013", - "device": "CGW452", - "scheduled_date": "2026-06-24", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAX004", - "device": "CGW453", - "scheduled_date": "2026-06-24", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "COERXAX001", - "device": "CGW453", - "scheduled_date": "2026-06-25", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "COERXAX002", - "device": "CGW453", - "scheduled_date": "2026-06-25", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX004", - "device": "CGW452", - "scheduled_date": "2026-06-25", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXBE016", - "device": "CGW453", - "scheduled_date": "2026-06-25", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE016", - "device": "CGW452", - "scheduled_date": "2026-06-25", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXBE019", - "device": "CGW453", - "scheduled_date": "2026-06-25", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE019", - "device": "CGW452", - "scheduled_date": "2026-06-25", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PTXAX034", - "device": "CGW453", - "scheduled_date": "2026-06-25", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COETXAX014", - "device": "CGW453", - "scheduled_date": "2026-06-25", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX034", - "device": "CGW452", - "scheduled_date": "2026-06-25", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE004", - "device": "CGW453", - "scheduled_date": "2026-06-25", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "COERXBE001", - "device": "CGW453", - "scheduled_date": "2026-06-26", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "COERXBE002", - "device": "CGW453", - "scheduled_date": "2026-06-26", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXBE004", - "device": "CGW452", - "scheduled_date": "2026-06-26", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAX029", - "device": "CGW453", - "scheduled_date": "2026-06-26", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX029", - "device": "CGW453", - "scheduled_date": "2026-06-26", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAX029", - "device": "CGW452", - "scheduled_date": "2026-06-26", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAX029", - "device": "CGW452", - "scheduled_date": "2026-06-26", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXAX007", - "device": "CGW453", - "scheduled_date": "2026-06-26", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COERXAX003", - "device": "CGW453", - "scheduled_date": "2026-06-26", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "COERXAX004", - "device": "CGW453", - "scheduled_date": "2026-06-26", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAX007", - "device": "CGW452", - "scheduled_date": "2026-06-26", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX004", - "device": "CGW453", - "scheduled_date": "2026-06-27", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "COETXAX001", - "device": "CGW453", - "scheduled_date": "2026-06-27", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "COETXAX002", - "device": "CGW453", - "scheduled_date": "2026-06-27", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAX004", - "device": "CGW452", - "scheduled_date": "2026-06-27", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX007", - "device": "CGW453", - "scheduled_date": "2026-06-27", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "COETXAX003", - "device": "CGW453", - "scheduled_date": "2026-06-27", - "shift_index": 2, - "sequence_in_shift": 1 - }, - { - "test_id": "COETXAX004", - "device": "CGW453", - "scheduled_date": "2026-06-27", - "shift_index": 2, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX007", - "device": "CGW452", - "scheduled_date": "2026-06-27", - "shift_index": 2, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAC011", - "device": "CGW453", - "scheduled_date": "2026-06-27", - "shift_index": 2, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAC011", - "device": "CGW453", - "scheduled_date": "2026-06-27", - "shift_index": 2, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAC011", - "device": "CGW452", - "scheduled_date": "2026-06-27", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAC011", - "device": "CGW452", - "scheduled_date": "2026-06-27", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAC012", - "device": "CGW453", - "scheduled_date": "2026-06-27", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAC012", - "device": "CGW453", - "scheduled_date": "2026-06-27", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAC012", - "device": "CGW452", - "scheduled_date": "2026-06-27", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAC012", - "device": "CGW452", - "scheduled_date": "2026-06-27", - "shift_index": 3, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PRXAC014", - "device": "CGW453", - "scheduled_date": "2026-06-28", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAC014", - "device": "CGW453", - "scheduled_date": "2026-06-28", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAC014", - "device": "CGW452", - "scheduled_date": "2026-06-28", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAC014", - "device": "CGW452", - "scheduled_date": "2026-06-28", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAC015", - "device": "CGW453", - "scheduled_date": "2026-06-28", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAC015", - "device": "CGW453", - "scheduled_date": "2026-06-28", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PRXAC015", - "device": "CGW452", - "scheduled_date": "2026-06-28", - "shift_index": 2, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAC015", - "device": "CGW452", - "scheduled_date": "2026-06-28", - "shift_index": 2, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAC017", - "device": "CGW453", - "scheduled_date": "2026-06-28", - "shift_index": 2, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAC017", - "device": "CGW453", - "scheduled_date": "2026-06-28", - "shift_index": 2, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAC017", - "device": "CGW452", - "scheduled_date": "2026-06-28", - "shift_index": 2, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAC017", - "device": "CGW452", - "scheduled_date": "2026-06-28", - "shift_index": 2, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PRXAC018", - "device": "CGW453", - "scheduled_date": "2026-06-28", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAC018", - "device": "CGW453", - "scheduled_date": "2026-06-28", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAC018", - "device": "CGW452", - "scheduled_date": "2026-06-28", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAC018", - "device": "CGW452", - "scheduled_date": "2026-06-28", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAX001", - "device": "CGW453", - "scheduled_date": "2026-06-28", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAX001", - "device": "CGW453", - "scheduled_date": "2026-06-28", - "shift_index": 3, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PRXAX001", - "device": "CGW452", - "scheduled_date": "2026-06-29", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAX001", - "device": "CGW452", - "scheduled_date": "2026-06-29", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX002", - "device": "CGW453", - "scheduled_date": "2026-06-29", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAX002", - "device": "CGW453", - "scheduled_date": "2026-06-29", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAX002", - "device": "CGW452", - "scheduled_date": "2026-06-29", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAX002", - "device": "CGW452", - "scheduled_date": "2026-06-29", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "COETXBE007", - "device": "CGW453", - "scheduled_date": "2026-06-29", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXBE007", - "device": "CGW453", - "scheduled_date": "2026-06-29", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COERXBE003", - "device": "CGW453", - "scheduled_date": "2026-06-29", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "COERXBE004", - "device": "CGW453", - "scheduled_date": "2026-06-29", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE007", - "device": "CGW452", - "scheduled_date": "2026-06-29", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE004", - "device": "CGW453", - "scheduled_date": "2026-06-30", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "COETXBE001", - "device": "CGW453", - "scheduled_date": "2026-06-30", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "COETXBE002", - "device": "CGW453", - "scheduled_date": "2026-06-30", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXBE004", - "device": "CGW452", - "scheduled_date": "2026-06-30", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE007", - "device": "CGW453", - "scheduled_date": "2026-06-30", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COETXBE003", - "device": "CGW453", - "scheduled_date": "2026-06-30", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "COETXBE004", - "device": "CGW453", - "scheduled_date": "2026-06-30", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXBE007", - "device": "CGW452", - "scheduled_date": "2026-06-30", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAX030", - "device": "CGW453", - "scheduled_date": "2026-07-01", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAX030", - "device": "CGW453", - "scheduled_date": "2026-07-01", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX030", - "device": "CGW452", - "scheduled_date": "2026-07-01", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAX030", - "device": "CGW452", - "scheduled_date": "2026-07-01", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAC002", - "device": "CGW453", - "scheduled_date": "2026-07-01", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAC002", - "device": "CGW453", - "scheduled_date": "2026-07-01", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAC002", - "device": "CGW452", - "scheduled_date": "2026-07-01", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAC002", - "device": "CGW452", - "scheduled_date": "2026-07-01", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAC003", - "device": "CGW453", - "scheduled_date": "2026-07-01", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAC003", - "device": "CGW453", - "scheduled_date": "2026-07-02", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAC003", - "device": "CGW452", - "scheduled_date": "2026-07-02", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAC003", - "device": "CGW452", - "scheduled_date": "2026-07-02", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAC005", - "device": "CGW453", - "scheduled_date": "2026-07-02", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAC005", - "device": "CGW453", - "scheduled_date": "2026-07-02", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAC005", - "device": "CGW452", - "scheduled_date": "2026-07-02", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAC005", - "device": "CGW452", - "scheduled_date": "2026-07-02", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXAC006", - "device": "CGW453", - "scheduled_date": "2026-07-02", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAC006", - "device": "CGW453", - "scheduled_date": "2026-07-02", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAC006", - "device": "CGW452", - "scheduled_date": "2026-07-02", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAC006", - "device": "CGW452", - "scheduled_date": "2026-07-02", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAC008", - "device": "CGW453", - "scheduled_date": "2026-07-02", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAC008", - "device": "CGW453", - "scheduled_date": "2026-07-03", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAC008", - "device": "CGW452", - "scheduled_date": "2026-07-03", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAC008", - "device": "CGW452", - "scheduled_date": "2026-07-03", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAC009", - "device": "CGW453", - "scheduled_date": "2026-07-03", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAC009", - "device": "CGW453", - "scheduled_date": "2026-07-03", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAC009", - "device": "CGW452", - "scheduled_date": "2026-07-03", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAC009", - "device": "CGW452", - "scheduled_date": "2026-07-03", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXAX003", - "device": "CGW453", - "scheduled_date": "2026-07-03", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAX003", - "device": "CGW453", - "scheduled_date": "2026-07-03", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX003", - "device": "CGW452", - "scheduled_date": "2026-07-03", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAX003", - "device": "CGW452", - "scheduled_date": "2026-07-03", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAX005", - "device": "CGW453", - "scheduled_date": "2026-07-03", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAX005", - "device": "CGW453", - "scheduled_date": "2026-07-04", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAX005", - "device": "CGW452", - "scheduled_date": "2026-07-04", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX005", - "device": "CGW452", - "scheduled_date": "2026-07-04", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAX006", - "device": "CGW453", - "scheduled_date": "2026-07-04", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX006", - "device": "CGW453", - "scheduled_date": "2026-07-04", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAX006", - "device": "CGW452", - "scheduled_date": "2026-07-04", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAX006", - "device": "CGW452", - "scheduled_date": "2026-07-04", - "shift_index": 2, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAX008", - "device": "CGW453", - "scheduled_date": "2026-07-04", - "shift_index": 2, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX008", - "device": "CGW453", - "scheduled_date": "2026-07-04", - "shift_index": 2, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAX008", - "device": "CGW452", - "scheduled_date": "2026-07-04", - "shift_index": 2, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX008", - "device": "CGW452", - "scheduled_date": "2026-07-04", - "shift_index": 2, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAX009", - "device": "CGW453", - "scheduled_date": "2026-07-04", - "shift_index": 2, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAX009", - "device": "CGW453", - "scheduled_date": "2026-07-04", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAX009", - "device": "CGW452", - "scheduled_date": "2026-07-04", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX009", - "device": "CGW452", - "scheduled_date": "2026-07-04", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAX011", - "device": "CGW453", - "scheduled_date": "2026-07-04", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX011", - "device": "CGW453", - "scheduled_date": "2026-07-04", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAX011", - "device": "CGW452", - "scheduled_date": "2026-07-04", - "shift_index": 3, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAX011", - "device": "CGW452", - "scheduled_date": "2026-07-05", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE001", - "device": "CGW453", - "scheduled_date": "2026-07-05", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE001", - "device": "CGW453", - "scheduled_date": "2026-07-05", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE001", - "device": "CGW452", - "scheduled_date": "2026-07-05", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE001", - "device": "CGW452", - "scheduled_date": "2026-07-05", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE002", - "device": "CGW453", - "scheduled_date": "2026-07-05", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE002", - "device": "CGW453", - "scheduled_date": "2026-07-05", - "shift_index": 2, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE002", - "device": "CGW452", - "scheduled_date": "2026-07-05", - "shift_index": 2, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE002", - "device": "CGW452", - "scheduled_date": "2026-07-05", - "shift_index": 2, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE003", - "device": "CGW453", - "scheduled_date": "2026-07-05", - "shift_index": 2, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE003", - "device": "CGW453", - "scheduled_date": "2026-07-05", - "shift_index": 2, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE003", - "device": "CGW452", - "scheduled_date": "2026-07-05", - "shift_index": 2, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE003", - "device": "CGW452", - "scheduled_date": "2026-07-05", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE005", - "device": "CGW453", - "scheduled_date": "2026-07-05", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE005", - "device": "CGW453", - "scheduled_date": "2026-07-05", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE005", - "device": "CGW452", - "scheduled_date": "2026-07-05", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE005", - "device": "CGW452", - "scheduled_date": "2026-07-05", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE006", - "device": "CGW453", - "scheduled_date": "2026-07-05", - "shift_index": 3, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE006", - "device": "CGW453", - "scheduled_date": "2026-07-06", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE006", - "device": "CGW452", - "scheduled_date": "2026-07-06", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE006", - "device": "CGW452", - "scheduled_date": "2026-07-06", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE008", - "device": "CGW453", - "scheduled_date": "2026-07-06", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE008", - "device": "CGW453", - "scheduled_date": "2026-07-06", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE008", - "device": "CGW452", - "scheduled_date": "2026-07-06", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE008", - "device": "CGW452", - "scheduled_date": "2026-07-06", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXAX014", - "device": "CGW453", - "scheduled_date": "2026-07-06", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAX014", - "device": "CGW453", - "scheduled_date": "2026-07-06", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX014", - "device": "CGW452", - "scheduled_date": "2026-07-06", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAX014", - "device": "CGW452", - "scheduled_date": "2026-07-06", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAX015", - "device": "CGW453", - "scheduled_date": "2026-07-06", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAX015", - "device": "CGW453", - "scheduled_date": "2026-07-07", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAX015", - "device": "CGW452", - "scheduled_date": "2026-07-07", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX015", - "device": "CGW452", - "scheduled_date": "2026-07-07", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAX017", - "device": "CGW453", - "scheduled_date": "2026-07-07", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX017", - "device": "CGW453", - "scheduled_date": "2026-07-07", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAX017", - "device": "CGW452", - "scheduled_date": "2026-07-07", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAX017", - "device": "CGW452", - "scheduled_date": "2026-07-07", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXAX018", - "device": "CGW453", - "scheduled_date": "2026-07-07", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAX018", - "device": "CGW453", - "scheduled_date": "2026-07-07", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX018", - "device": "CGW452", - "scheduled_date": "2026-07-07", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAX018", - "device": "CGW452", - "scheduled_date": "2026-07-07", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAX020", - "device": "CGW453", - "scheduled_date": "2026-07-07", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAX020", - "device": "CGW453", - "scheduled_date": "2026-07-08", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAX020", - "device": "CGW452", - "scheduled_date": "2026-07-08", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX020", - "device": "CGW452", - "scheduled_date": "2026-07-08", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAX021", - "device": "CGW453", - "scheduled_date": "2026-07-08", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX021", - "device": "CGW453", - "scheduled_date": "2026-07-08", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAX021", - "device": "CGW452", - "scheduled_date": "2026-07-08", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAX021", - "device": "CGW452", - "scheduled_date": "2026-07-08", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXAX032", - "device": "CGW453", - "scheduled_date": "2026-07-08", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAX032", - "device": "CGW453", - "scheduled_date": "2026-07-08", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX032", - "device": "CGW452", - "scheduled_date": "2026-07-08", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAX032", - "device": "CGW452", - "scheduled_date": "2026-07-08", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXAX033", - "device": "CGW453", - "scheduled_date": "2026-07-08", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXAX033", - "device": "CGW453", - "scheduled_date": "2026-07-09", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXAX033", - "device": "CGW452", - "scheduled_date": "2026-07-09", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXAX033", - "device": "CGW452", - "scheduled_date": "2026-07-09", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXAX035", - "device": "CGW453", - "scheduled_date": "2026-07-09", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXAX035", - "device": "CGW453", - "scheduled_date": "2026-07-09", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXAX035", - "device": "CGW452", - "scheduled_date": "2026-07-09", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXAX035", - "device": "CGW452", - "scheduled_date": "2026-07-09", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXAX036", - "device": "CGW453", - "scheduled_date": "2026-07-09", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXAX036", - "device": "CGW453", - "scheduled_date": "2026-07-09", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXAX036", - "device": "CGW452", - "scheduled_date": "2026-07-09", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXAX036", - "device": "CGW452", - "scheduled_date": "2026-07-09", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXBE009", - "device": "CGW453", - "scheduled_date": "2026-07-09", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXBE009", - "device": "CGW453", - "scheduled_date": "2026-07-10", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE009", - "device": "CGW452", - "scheduled_date": "2026-07-10", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE009", - "device": "CGW452", - "scheduled_date": "2026-07-10", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE011", - "device": "CGW453", - "scheduled_date": "2026-07-10", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE011", - "device": "CGW453", - "scheduled_date": "2026-07-10", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE011", - "device": "CGW452", - "scheduled_date": "2026-07-10", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE011", - "device": "CGW452", - "scheduled_date": "2026-07-10", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXBE012", - "device": "CGW453", - "scheduled_date": "2026-07-10", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXBE012", - "device": "CGW453", - "scheduled_date": "2026-07-10", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXBE012", - "device": "CGW452", - "scheduled_date": "2026-07-10", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXBE012", - "device": "CGW452", - "scheduled_date": "2026-07-10", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXBE015", - "device": "CGW453", - "scheduled_date": "2026-07-10", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXBE015", - "device": "CGW453", - "scheduled_date": "2026-07-11", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE015", - "device": "CGW452", - "scheduled_date": "2026-07-11", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE015", - "device": "CGW452", - "scheduled_date": "2026-07-11", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE018", - "device": "CGW453", - "scheduled_date": "2026-07-11", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE018", - "device": "CGW453", - "scheduled_date": "2026-07-11", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE018", - "device": "CGW452", - "scheduled_date": "2026-07-11", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE018", - "device": "CGW452", - "scheduled_date": "2026-07-11", - "shift_index": 2, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE021", - "device": "CGW453", - "scheduled_date": "2026-07-11", - "shift_index": 2, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE021", - "device": "CGW453", - "scheduled_date": "2026-07-11", - "shift_index": 2, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE021", - "device": "CGW452", - "scheduled_date": "2026-07-11", - "shift_index": 2, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE021", - "device": "CGW452", - "scheduled_date": "2026-07-11", - "shift_index": 2, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE030", - "device": "CGW453", - "scheduled_date": "2026-07-11", - "shift_index": 2, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE030", - "device": "CGW453", - "scheduled_date": "2026-07-11", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE030", - "device": "CGW452", - "scheduled_date": "2026-07-11", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE030", - "device": "CGW452", - "scheduled_date": "2026-07-11", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE033", - "device": "CGW453", - "scheduled_date": "2026-07-11", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE033", - "device": "CGW453", - "scheduled_date": "2026-07-11", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE033", - "device": "CGW452", - "scheduled_date": "2026-07-11", - "shift_index": 3, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE033", - "device": "CGW452", - "scheduled_date": "2026-07-12", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE036", - "device": "CGW453", - "scheduled_date": "2026-07-12", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE036", - "device": "CGW453", - "scheduled_date": "2026-07-12", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE036", - "device": "CGW452", - "scheduled_date": "2026-07-12", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE036", - "device": "CGW452", - "scheduled_date": "2026-07-12", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE014", - "device": "CGW453", - "scheduled_date": "2026-07-13", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXBE014", - "device": "CGW453", - "scheduled_date": "2026-07-13", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXBE014", - "device": "CGW452", - "scheduled_date": "2026-07-13", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXBE014", - "device": "CGW452", - "scheduled_date": "2026-07-13", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXBE017", - "device": "CGW453", - "scheduled_date": "2026-07-13", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXBE017", - "device": "CGW453", - "scheduled_date": "2026-07-14", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE017", - "device": "CGW452", - "scheduled_date": "2026-07-14", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE017", - "device": "CGW452", - "scheduled_date": "2026-07-14", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE020", - "device": "CGW453", - "scheduled_date": "2026-07-14", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE020", - "device": "CGW453", - "scheduled_date": "2026-07-14", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE020", - "device": "CGW452", - "scheduled_date": "2026-07-14", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE020", - "device": "CGW452", - "scheduled_date": "2026-07-14", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "P2PRXBE029", - "device": "CGW453", - "scheduled_date": "2026-07-14", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PTXBE029", - "device": "CGW453", - "scheduled_date": "2026-07-14", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PRXBE029", - "device": "CGW452", - "scheduled_date": "2026-07-14", - "shift_index": 3, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PTXBE029", - "device": "CGW452", - "scheduled_date": "2026-07-14", - "shift_index": 3, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PRXBE032", - "device": "CGW453", - "scheduled_date": "2026-07-14", - "shift_index": 3, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PTXBE032", - "device": "CGW453", - "scheduled_date": "2026-07-15", - "shift_index": 1, - "sequence_in_shift": 1 - }, - { - "test_id": "P2PRXBE032", - "device": "CGW452", - "scheduled_date": "2026-07-15", - "shift_index": 1, - "sequence_in_shift": 2 - }, - { - "test_id": "P2PTXBE032", - "device": "CGW452", - "scheduled_date": "2026-07-15", - "shift_index": 1, - "sequence_in_shift": 3 - }, - { - "test_id": "P2PRXBE035", - "device": "CGW453", - "scheduled_date": "2026-07-15", - "shift_index": 1, - "sequence_in_shift": 4 - }, - { - "test_id": "P2PTXBE035", - "device": "CGW453", - "scheduled_date": "2026-07-15", - "shift_index": 1, - "sequence_in_shift": 5 - }, - { - "test_id": "P2PRXBE035", - "device": "CGW452", - "scheduled_date": "2026-07-15", - "shift_index": 1, - "sequence_in_shift": 6 - }, - { - "test_id": "P2PTXBE035", - "device": "CGW452", - "scheduled_date": "2026-07-15", - "shift_index": 1, - "sequence_in_shift": 7 - }, - { - "test_id": "COETXBE008", - "device": "CGW453", - "scheduled_date": "2026-07-15", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COETXBE009", - "device": "CGW453", - "scheduled_date": "2026-07-15", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "COETXBE012", - "device": "CGW453", - "scheduled_date": "2026-07-16", - "shift_index": 3, - "sequence_in_shift": 1 - }, - { - "test_id": "COETXBE013", - "device": "CGW453", - "scheduled_date": "2026-07-16", - "shift_index": 3, - "sequence_in_shift": 2 - }, - { - "test_id": "COETXBE014", - "device": "CGW453", - "scheduled_date": "2026-07-16", - "shift_index": 3, - "sequence_in_shift": 3 - } -]\nCOMPLETION_DATE: 2026-07-16\n \ No newline at end of file diff --git a/backend/parser.py b/backend/parser.py index f2234b7..0ff6a0b 100644 --- a/backend/parser.py +++ b/backend/parser.py @@ -5,7 +5,7 @@ from pathlib import Path from db import DEVICE_DUT, DEVICE_REF, TestRecord -REQUIRED_COLUMNS = [ +P2P_COE_REQUIRED_COLUMNS = [ "Priority", "Index", "Interferer", @@ -34,6 +34,37 @@ REQUIRED_COLUMNS = [ "2G STA", ] +P3P_REQUIRED_COLUMNS = [ + "Priority", + "Index", + "Throttled", + "Rotation", + "TC ID", + "Band", + "6GHz Power Mode", + "Station 1 Test Point", + "Station 1 Channel", + "Station 1 Bandwidth", + "Station 1 RSSI", + "Station 1 Direction", + "Station 1 Rate", + "Station 1 STA", + "Station 2 Test Point", + "Station 2 Channel", + "Station 2 Bandwidth", + "Station 2 RSSI", + "Station 2 Direction", + "Station 2 Rate", + "Station 2 STA", + "Station 3 Test Point", + "Station 3 Channel", + "Station 3 Bandwidth", + "Station 3 RSSI", + "Station 3 Direction", + "Station 3 Rate", + "Station 3 STA", +] + RUNTIME_DEFAULTS = { "P2P": 80, "COE": 115, @@ -50,28 +81,84 @@ class CsvValidationError(ValueError): pass -def parse_target_csv(csv_path: str | Path) -> ParseResult: - path = Path(csv_path) - if not path.exists(): - raise FileNotFoundError(f"CSV file not found: {path}") +def _columns_missing(normalized_fieldnames: set[str], required_columns: list[str]) -> list[str]: + return [ + column + for column in required_columns + if column.strip().upper() not in normalized_fieldnames + ] + +def _detect_csv_format(normalized_fieldnames: set[str]) -> str: + p2p_coe_missing = _columns_missing(normalized_fieldnames, P2P_COE_REQUIRED_COLUMNS) + if not p2p_coe_missing: + return "p2p_coe" + + p3p_missing = _columns_missing(normalized_fieldnames, P3P_REQUIRED_COLUMNS) + if not p3p_missing: + return "p3p" + + raise CsvValidationError( + "CSV format not recognized. Missing columns for P2P/COE format: " + f"{', '.join(p2p_coe_missing)}; missing columns for P3P format: {', '.join(p3p_missing)}" + ) + + +def parse_target_csv(csv_path: str | Path | list[str | Path] | tuple[str | Path, ...]) -> ParseResult: + paths = _resolve_csv_paths(csv_path) + all_tests: list[TestRecord] = [] + all_warnings: list[str] = [] + seen_test_keys: set[tuple[str, str]] = set() + + for path in paths: + parsed = _parse_single_csv(path) + all_warnings.extend(parsed.warnings) + for record in parsed.tests: + key = (record.test_id, record.device) + if key in seen_test_keys: + all_warnings.append( + f"File {path.name}: duplicate test/device '{record.test_id}/{record.device}', record skipped." + ) + continue + seen_test_keys.add(key) + all_tests.append(record) + + return ParseResult(tests=all_tests, warnings=all_warnings) + + + +def _resolve_csv_paths(csv_path: str | Path | list[str | Path] | tuple[str | Path, ...]) -> list[Path]: + if isinstance(csv_path, (str, Path)): + paths = [Path(csv_path)] + else: + paths = [Path(item) for item in csv_path] + + resolved_paths: list[Path] = [] + for path in paths: + if path.is_dir(): + resolved_paths.extend(sorted(path.glob("*.csv"))) + else: + resolved_paths.append(path) + + if not resolved_paths: + raise FileNotFoundError("No CSV files found to parse.") + + for path in resolved_paths: + if not path.exists(): + raise FileNotFoundError(f"CSV file not found: {path}") + + return resolved_paths + + + +def _parse_single_csv(path: Path) -> ParseResult: with path.open("r", encoding="utf-8-sig", newline="") as handle: reader = csv.DictReader(handle) if not reader.fieldnames: raise CsvValidationError("CSV is missing a header row.") normalized_fieldnames = {name.strip().upper() for name in reader.fieldnames if name} - - # Check for required columns - missing_columns = [ - c - for c in REQUIRED_COLUMNS - if c.strip().upper() not in normalized_fieldnames - ] - if missing_columns: - raise CsvValidationError( - f"CSV is missing required columns: {', '.join(missing_columns)}" - ) + csv_format = _detect_csv_format(normalized_fieldnames) tests: list[TestRecord] = [] warnings: list[str] = [] @@ -82,31 +169,33 @@ def parse_target_csv(csv_path: str | Path) -> ParseResult: for row_num, row in enumerate(reader, start=2): test_id = (row.get("TC ID") or "").strip() if not test_id: - warnings.append(f"Row {row_num}: missing TC ID, row skipped.") + warnings.append(f"File {path.name}, row {row_num}: missing TC ID, row skipped.") continue if test_id in seen_test_ids: - warnings.append(f"Row {row_num}: duplicate TC ID '{test_id}', row skipped.") + warnings.append(f"File {path.name}, row {row_num}: duplicate TC ID '{test_id}', row skipped.") continue seen_test_ids.add(test_id) + throttled = _normalize_yes_no(_row_get(row, "Throttled")) if csv_format == "p3p" else False test_type = _infer_test_type(test_id) rx_tx = _infer_rx_tx(test_id) rotation = _empty_to_none(_row_get(row, "Rotation")) - has_coe_pair = _normalize_yes_no(_row_get(row, "COE Pair")) - config = _build_config(row) - signature = _victim_band_signature(row) + has_coe_pair = _normalize_yes_no(_row_get(row, "COE Pair")) if csv_format == "p2p_coe" else False + config = _build_config(row, csv_format) + signature = _victim_band_signature(row) if csv_format == "p2p_coe" else None estimated_minutes = RUNTIME_DEFAULTS.get(test_type) - victim_band = _normalize_victim_band(_row_get(row, "Victim Band")) - - # Default priority based on test type and COE pairing + victim_band_source = "Victim Band" if csv_format == "p2p_coe" else "Band" + victim_band = _normalize_victim_band(_row_get(row, victim_band_source)) + + # Default priority based on test type and COE pairing. if test_type == "P2P": priority = 2 if has_coe_pair else 3 elif test_type == "COE": priority = 3 else: priority = 4 - + record = TestRecord( test_id=test_id, device=DEVICE_DUT, @@ -118,6 +207,7 @@ def parse_target_csv(csv_path: str | Path) -> ParseResult: priority=priority, victim_band=victim_band, config=config, + throttled=throttled, estimated_minutes=estimated_minutes, status="pending", excluded=False, @@ -155,6 +245,7 @@ def parse_target_csv(csv_path: str | Path) -> ParseResult: priority=record.priority, victim_band=record.victim_band, config=record.config, + throttled=record.throttled, estimated_minutes=record.estimated_minutes, status=record.status, excluded=record.excluded, @@ -252,7 +343,7 @@ def _normalize_yes_no(value: str | None) -> bool: return _normalize_value(value) == "YES" -def _build_config(row: dict[str, str]) -> dict[str, dict[str, str | None]]: +def _build_legacy_config(row: dict[str, str]) -> dict[str, dict[str, str | None]]: return { "5G": { "test_point": _empty_to_none(_row_get(row, "5G Test Point")), @@ -282,6 +373,44 @@ def _build_config(row: dict[str, str]) -> dict[str, dict[str, str | None]]: } +def _build_p3p_config(row: dict[str, str]) -> dict[str, dict[str, str | None]]: + return { + "Station 1": { + "test_point": _empty_to_none(_row_get(row, "Station 1 Test Point")), + "channel": _empty_to_none(_row_get(row, "Station 1 Channel")), + "bandwidth": _empty_to_none(_row_get(row, "Station 1 Bandwidth")), + "rssi": _empty_to_none(_row_get(row, "Station 1 RSSI")), + "direction": _empty_to_none(_row_get(row, "Station 1 Direction")), + "rate": _empty_to_none(_row_get(row, "Station 1 Rate")), + "sta": _empty_to_none(_row_get(row, "Station 1 STA")), + }, + "Station 2": { + "test_point": _empty_to_none(_row_get(row, "Station 2 Test Point")), + "channel": _empty_to_none(_row_get(row, "Station 2 Channel")), + "bandwidth": _empty_to_none(_row_get(row, "Station 2 Bandwidth")), + "rssi": _empty_to_none(_row_get(row, "Station 2 RSSI")), + "direction": _empty_to_none(_row_get(row, "Station 2 Direction")), + "rate": _empty_to_none(_row_get(row, "Station 2 Rate")), + "sta": _empty_to_none(_row_get(row, "Station 2 STA")), + }, + "Station 3": { + "test_point": _empty_to_none(_row_get(row, "Station 3 Test Point")), + "channel": _empty_to_none(_row_get(row, "Station 3 Channel")), + "bandwidth": _empty_to_none(_row_get(row, "Station 3 Bandwidth")), + "rssi": _empty_to_none(_row_get(row, "Station 3 RSSI")), + "direction": _empty_to_none(_row_get(row, "Station 3 Direction")), + "rate": _empty_to_none(_row_get(row, "Station 3 Rate")), + "sta": _empty_to_none(_row_get(row, "Station 3 STA")), + }, + } + + +def _build_config(row: dict[str, str], csv_format: str) -> dict[str, dict[str, str | None]]: + if csv_format == "p3p": + return _build_p3p_config(row) + return _build_legacy_config(row) + + def _row_get(row: dict[str, str], key: str) -> str | None: if key in row: return row.get(key) diff --git a/backend/scheduler.py b/backend/scheduler.py index 3577e14..04a3713 100644 --- a/backend/scheduler.py +++ b/backend/scheduler.py @@ -28,6 +28,7 @@ class SchedulerTest: has_coe_pair: bool coe_pairing: list[str] config: dict[str, dict[str, str | None]] + throttled: bool estimated_minutes: int priority: int raw_payload: dict[str, Any]