Sprint 65: Parallel Pair Upgrades and Queue Optimization — Steps 879-888

Implements priority-aware pair-upgrade queue with starvation prevention:
- PairUpgradeQueue: enqueue/dequeue/getActive sorted by priority (step 879)
- UpgradePriorityPolicy: critical/revenue/coverage/experimental classes (step 880)
- ParallelDispatchOptimizer: schedule N pairs with blocked-pair constraints (step 881)
- StarvationPrevention: detect and promote starved pairs (step 882)
- QueueHealthScorer: stall-rate-based health scoring (step 883)
- RetryBackoffStrategy: exponential backoff with max-attempts guard (step 884)
- whetstone_enqueue_pair_upgrade MCP tool (step 885)
- whetstone_get_upgrade_queue MCP tool with priority sorting (step 886)
- UpgradeQueueObservabilityPanel: snapshot model for queue visibility (step 887)
- Sprint65IntegrationSummary (step 888)

All 10 steps passing (94 tests). Routing rule: critical-tier regressions
preempt all experimental upgrades.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Bill
2026-02-22 18:58:04 -07:00
parent 484d9e3f8c
commit 0282e7ebb7
22 changed files with 932 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
// Step 879: Pair-upgrade queue model (12 tests)
#include "graduation/PairUpgradeQueue.h"
#include <iostream>
static int p=0,f=0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){T(enqueue_valid);
PairUpgradeQueue q;
C(q.enqueue({"E-1","py->cpp","critical",4,true}),"enqueue");P();}
void t2(){T(enqueue_empty_pair_fails);
PairUpgradeQueue q; std::string err;
C(!q.enqueue({"E-1","","critical",4,true},&err)&&err=="pair_id_missing","fail");P();}
void t3(){T(enqueue_empty_id_fails);
PairUpgradeQueue q; std::string err;
C(!q.enqueue({"","py->cpp","critical",4,true},&err)&&err=="entry_id_missing","fail");P();}
void t4(){T(active_count_increments);
PairUpgradeQueue q;
q.enqueue({"E-1","py->cpp","critical",4,true});
q.enqueue({"E-2","rust->go","coverage",2,true});
C(q.activeCount()==2,"count");P();}
void t5(){T(dequeue_removes);
PairUpgradeQueue q;
q.enqueue({"E-1","py->cpp","critical",4,true});
C(q.dequeue("E-1"),"dequeue");P();}
void t6(){T(active_count_after_dequeue);
PairUpgradeQueue q;
q.enqueue({"E-1","py->cpp","critical",4,true});
q.dequeue("E-1");
C(q.activeCount()==0,"count 0");P();}
void t7(){T(dequeue_unknown_fails);
PairUpgradeQueue q;
C(!q.dequeue("NONEXISTENT"),"fail");P();}
void t8(){T(get_active_sorted_by_priority);
PairUpgradeQueue q;
q.enqueue({"E-1","py->cpp","experimental",1,true});
q.enqueue({"E-2","rust->go","critical",4,true});
auto a=q.getActive();
C(a[0].priorityLevel==4,"sorted");P();}
void t9(){T(get_active_excludes_dequeued);
PairUpgradeQueue q;
q.enqueue({"E-1","py->cpp","critical",4,true});
q.enqueue({"E-2","rust->go","coverage",2,true});
q.dequeue("E-1");
auto a=q.getActive();
C(a.size()==1,"size");P();}
void t10(){T(to_json_has_entry_id);
UpgradeQueueEntry e{"E-1","py->cpp","critical",4,true};
auto j=PairUpgradeQueue::toJson(e);
C(j.contains("entry_id"),"json");P();}
void t11(){T(to_json_has_priority);
UpgradeQueueEntry e{"E-1","py->cpp","critical",4,true};
auto j=PairUpgradeQueue::toJson(e);
C(j["priority"]=="critical","priority");P();}
void t12(){T(empty_queue_active_zero);
PairUpgradeQueue q;
C(q.activeCount()==0,"zero");P();}
int main(){
std::cout<<"Step 879: Pair-upgrade queue model\n";
t1();t2();t3();t4();t5();t6();t7();t8();t9();t10();t11();t12();
std::cout<<"\nResults: "<<p<<"/"<<(p+f)<<" passed\n";
return f?1:0;
}

View File

@@ -0,0 +1,44 @@
// Step 880: Priority policy (10 tests)
#include "graduation/UpgradePriorityPolicy.h"
#include <iostream>
static int p=0,f=0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){T(critical_level_4);
auto r=UpgradePriorityPolicy::classify("py->cpp","critical");
C(r.priorityLevel==4,"level");P();}
void t2(){T(revenue_level_3);
auto r=UpgradePriorityPolicy::classify("py->cpp","revenue");
C(r.priorityLevel==3,"level");P();}
void t3(){T(coverage_level_2);
auto r=UpgradePriorityPolicy::classify("py->cpp","coverage");
C(r.priorityLevel==2,"level");P();}
void t4(){T(experimental_level_1);
auto r=UpgradePriorityPolicy::classify("py->cpp","experimental");
C(r.priorityLevel==1,"level");P();}
void t5(){T(critical_preempts_experimental);
auto r=UpgradePriorityPolicy::classify("py->cpp","critical");
C(r.preemptsExperimental,"preempt");P();}
void t6(){T(revenue_no_preempt);
auto r=UpgradePriorityPolicy::classify("py->cpp","revenue");
C(!r.preemptsExperimental,"no preempt");P();}
void t7(){T(unknown_defaults_experimental);
auto r=UpgradePriorityPolicy::classify("py->cpp","unknown");
C(r.priorityClass=="experimental","default");P();}
void t8(){T(pair_id_stored);
auto r=UpgradePriorityPolicy::classify("rust->go","critical");
C(r.pairId=="rust->go","pairId");P();}
void t9(){T(validate_known_class);
C(UpgradePriorityPolicy::validate("critical"),"valid");P();}
void t10(){T(validate_unknown_class_fails);
C(!UpgradePriorityPolicy::validate("unknown"),"invalid");P();}
int main(){
std::cout<<"Step 880: Priority policy\n";
t1();t2();t3();t4();t5();t6();t7();t8();t9();t10();
std::cout<<"\nResults: "<<p<<"/"<<(p+f)<<" passed\n";
return f?1:0;
}

View File

@@ -0,0 +1,50 @@
// Step 881: Parallel dispatch optimizer (10 tests)
#include "graduation/ParallelDispatchOptimizer.h"
#include <iostream>
static int p=0,f=0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){T(schedules_up_to_max);
auto plan=ParallelDispatchOptimizer::optimize({"a","b","c"},2);
C(plan.scheduledCount==2,"count");P();}
void t2(){T(max_parallelism_stored);
auto plan=ParallelDispatchOptimizer::optimize({"a","b"},3);
C(plan.maxParallelism==3,"max");P();}
void t3(){T(slot_count_equals_pairs);
auto plan=ParallelDispatchOptimizer::optimize({"a","b","c"},3);
C(plan.slots.size()==3,"slots");P();}
void t4(){T(blocked_pairs_not_scheduled);
auto plan=ParallelDispatchOptimizer::optimize({"a","b","c"},3,{"b"});
bool b_scheduled=false;
for(auto& s:plan.slots) if(s.pairId=="b"&&s.scheduled) b_scheduled=true;
C(!b_scheduled,"not sched");P();}
void t5(){T(slot_ids_sequential);
auto plan=ParallelDispatchOptimizer::optimize({"a","b"},2);
C(plan.slots[0].slotId=="slot-1"&&plan.slots[1].slotId=="slot-2","ids");P();}
void t6(){T(empty_pairs_zero_scheduled);
auto plan=ParallelDispatchOptimizer::optimize({},2);
C(plan.scheduledCount==0,"zero");P();}
void t7(){T(more_pairs_than_max);
auto plan=ParallelDispatchOptimizer::optimize({"a","b","c","d"},2);
C(plan.scheduledCount==2,"capped");P();}
void t8(){T(all_pairs_if_within_max);
auto plan=ParallelDispatchOptimizer::optimize({"a","b"},5);
C(plan.scheduledCount==2,"all");P();}
void t9(){T(to_json_has_scheduled_count);
auto plan=ParallelDispatchOptimizer::optimize({"a","b"},2);
auto j=ParallelDispatchOptimizer::toJson(plan);
C(j.contains("scheduled_count"),"json");P();}
void t10(){T(to_json_slots_array);
auto plan=ParallelDispatchOptimizer::optimize({"a"},1);
auto j=ParallelDispatchOptimizer::toJson(plan);
C(j["slots"].is_array(),"slots");P();}
int main(){
std::cout<<"Step 881: Parallel dispatch optimizer\n";
t1();t2();t3();t4();t5();t6();t7();t8();t9();t10();
std::cout<<"\nResults: "<<p<<"/"<<(p+f)<<" passed\n";
return f?1:0;
}

View File

@@ -0,0 +1,51 @@
// Step 882: Starvation prevention mechanism (10 tests)
#include "graduation/StarvationPrevention.h"
#include <iostream>
static int p=0,f=0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){T(below_threshold_not_at_risk);
auto e=StarvationPrevention::assess("py->cpp",3,5);
C(!e.atRisk,"not risk");P();}
void t2(){T(at_threshold_at_risk);
auto e=StarvationPrevention::assess("py->cpp",5,5);
C(e.atRisk,"risk");P();}
void t3(){T(above_threshold_at_risk);
auto e=StarvationPrevention::assess("py->cpp",8,5);
C(e.atRisk,"risk");P();}
void t4(){T(at_risk_promoted);
auto e=StarvationPrevention::assess("py->cpp",5,5);
C(e.promoted,"promoted");P();}
void t5(){T(not_at_risk_not_promoted);
auto e=StarvationPrevention::assess("py->cpp",2,5);
C(!e.promoted,"not promoted");P();}
void t6(){T(pair_id_set);
auto e=StarvationPrevention::assess("rust->go",3,5);
C(e.pairId=="rust->go","pairId");P();}
void t7(){T(wait_cycles_stored);
auto e=StarvationPrevention::assess("py->cpp",7,5);
C(e.waitCycles==7,"cycles");P();}
void t8(){T(count_at_risk_zero);
std::vector<StarvationRiskEntry> v={
StarvationPrevention::assess("a",2,5),
StarvationPrevention::assess("b",3,5)};
C(StarvationPrevention::countAtRisk(v)==0,"zero");P();}
void t9(){T(count_at_risk_nonzero);
std::vector<StarvationRiskEntry> v={
StarvationPrevention::assess("a",6,5),
StarvationPrevention::assess("b",2,5)};
C(StarvationPrevention::countAtRisk(v)==1,"one");P();}
void t10(){T(to_json_has_at_risk);
auto e=StarvationPrevention::assess("py->cpp",6,5);
auto j=StarvationPrevention::toJson(e);
C(j.contains("at_risk"),"json");P();}
int main(){
std::cout<<"Step 882: Starvation prevention\n";
t1();t2();t3();t4();t5();t6();t7();t8();t9();t10();
std::cout<<"\nResults: "<<p<<"/"<<(p+f)<<" passed\n";
return f?1:0;
}

View File

@@ -0,0 +1,51 @@
// Step 883: Queue health scoring model (10 tests)
#include "graduation/QueueHealthScorer.h"
#include <iostream>
static int p=0,f=0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){T(queue_id_set);
auto h=QueueHealthScorer::score("q1",5,0,10);
C(h.queueId=="q1","id");P();}
void t2(){T(no_stall_healthy);
auto h=QueueHealthScorer::score("q1",5,0,10);
C(h.label=="healthy","healthy");P();}
void t3(){T(all_stalled_critical);
auto h=QueueHealthScorer::score("q1",0,10,10);
C(h.label=="critical","critical");P();}
void t4(){T(score_in_range);
auto h=QueueHealthScorer::score("q1",5,2,10);
C(h.score>=0.0f&&h.score<=1.0f,"range");P();}
void t5(){T(active_count_stored);
auto h=QueueHealthScorer::score("q1",7,1,10);
C(h.activeCount==7,"active");P();}
void t6(){T(stalled_count_stored);
auto h=QueueHealthScorer::score("q1",5,3,10);
C(h.stalledCount==3,"stalled");P();}
void t7(){T(zero_counts_healthy);
auto h=QueueHealthScorer::score("q1",0,0,10);
C(h.score>=0.0f,"zero");P();}
void t8(){T(degraded_label);
// 50% stall rate → score = 1 - 0.5*0.7 = 0.65 → healthy? Actually let me think...
// stallRate = 5/10 = 0.5, score = 1 - 0.5*0.7 = 0.65 → healthy
// Let's use stallRate=0.9 → score = 1-0.9*0.7 = 0.37 → degraded
auto h=QueueHealthScorer::score("q1",1,9,20);
C(h.label=="degraded"||h.label=="critical","degraded or critical");P();}
void t9(){T(to_json_has_score);
auto h=QueueHealthScorer::score("q1",5,0,10);
auto j=QueueHealthScorer::toJson(h);
C(j.contains("score"),"json");P();}
void t10(){T(to_json_has_label);
auto h=QueueHealthScorer::score("q1",5,0,10);
auto j=QueueHealthScorer::toJson(h);
C(j.contains("label"),"label");P();}
int main(){
std::cout<<"Step 883: Queue health scoring\n";
t1();t2();t3();t4();t5();t6();t7();t8();t9();t10();
std::cout<<"\nResults: "<<p<<"/"<<(p+f)<<" passed\n";
return f?1:0;
}

View File

@@ -0,0 +1,41 @@
// Step 884: Retry/backoff strategy for unstable pairs (8 tests)
#include "graduation/RetryBackoffStrategy.h"
#include <iostream>
static int p=0,f=0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){T(first_attempt_should_retry);
auto d=RetryBackoffStrategy::decide("py->cpp",0,3,100);
C(d.shouldRetry,"retry");P();}
void t2(){T(max_attempts_no_retry);
auto d=RetryBackoffStrategy::decide("py->cpp",3,3,100);
C(!d.shouldRetry,"no retry");P();}
void t3(){T(pair_id_set);
auto d=RetryBackoffStrategy::decide("rust->go",0,3,100);
C(d.pairId=="rust->go","pairId");P();}
void t4(){T(attempt_number_stored);
auto d=RetryBackoffStrategy::decide("py->cpp",2,3,100);
C(d.attemptNumber==2,"attempt");P();}
void t5(){T(backoff_increases_with_attempt);
auto d0=RetryBackoffStrategy::decide("py->cpp",0,3,100);
auto d1=RetryBackoffStrategy::decide("py->cpp",1,3,100);
C(d1.backoffMs>d0.backoffMs,"backoff");P();}
void t6(){T(no_retry_zero_backoff);
auto d=RetryBackoffStrategy::decide("py->cpp",3,3,100);
C(d.backoffMs==0,"zero");P();}
void t7(){T(reason_will_retry);
auto d=RetryBackoffStrategy::decide("py->cpp",0,3,100);
C(d.reason=="will_retry","reason");P();}
void t8(){T(reason_max_attempts);
auto d=RetryBackoffStrategy::decide("py->cpp",3,3,100);
C(d.reason=="max_attempts_reached","reason");P();}
int main(){
std::cout<<"Step 884: Retry/backoff strategy\n";
t1();t2();t3();t4();t5();t6();t7();t8();
std::cout<<"\nResults: "<<p<<"/"<<(p+f)<<" passed\n";
return f?1:0;
}

View File

@@ -0,0 +1,65 @@
// Step 885: whetstone_enqueue_pair_upgrade MCP tool (8 tests)
#include "MCPServer.h"
#include <iostream>
static int p=0,f=0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){T(tool_registered);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/list"},{"params",{}}});
bool found=false;
for(auto& t:r["result"]["tools"]) if(t["name"]=="whetstone_enqueue_pair_upgrade") found=true;
C(found,"tool found");P();}
void t2(){T(no_pair_id_fails);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",nlohmann::json::object()}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(!res["success"].get<bool>(),"fail");P();}
void t3(){T(invalid_priority_fails);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id","py->cpp"},{"priority","bogus"}}}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(!res["success"].get<bool>(),"fail");P();}
void t4(){T(valid_enqueue_succeeds);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id","py->cpp"},{"priority","critical"}}}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res["success"].get<bool>(),"success");P();}
void t5(){T(entry_id_in_response);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id","py->cpp"},{"priority","revenue"}}}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res.contains("entry_id"),"entry_id");P();}
void t6(){T(priority_class_in_response);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id","py->cpp"},{"priority","critical"}}}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res["priority_class"]=="critical","priority");P();}
void t7(){T(queue_size_increments);
MCPServer srv;
srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id","py->cpp"},{"priority","coverage"}}}}}});
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",2},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id","rust->go"},{"priority","revenue"}}}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res["queue_size"].get<int>()==2,"size");P();}
void t8(){T(priority_level_in_response);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id","py->cpp"},{"priority","critical"}}}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res["priority_level"].get<int>()==4,"level");P();}
int main(){
std::cout<<"Step 885: whetstone_enqueue_pair_upgrade\n";
t1();t2();t3();t4();t5();t6();t7();t8();
std::cout<<"\nResults: "<<p<<"/"<<(p+f)<<" passed\n";
return f?1:0;
}

View File

@@ -0,0 +1,71 @@
// Step 886: whetstone_get_upgrade_queue MCP tool (8 tests)
#include "MCPServer.h"
#include <iostream>
static int p=0,f=0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){T(tool_registered);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/list"},{"params",{}}});
bool found=false;
for(auto& t:r["result"]["tools"]) if(t["name"]=="whetstone_get_upgrade_queue") found=true;
C(found,"tool found");P();}
void t2(){T(empty_queue_returns_success);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_get_upgrade_queue"},{"arguments",nlohmann::json::object()}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res["success"].get<bool>(),"success");P();}
void t3(){T(entries_array_present);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_get_upgrade_queue"},{"arguments",nlohmann::json::object()}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res["entries"].is_array(),"entries");P();}
void t4(){T(total_active_field);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_get_upgrade_queue"},{"arguments",nlohmann::json::object()}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res.contains("total_active"),"total");P();}
void t5(){T(enqueue_then_get);
MCPServer srv;
srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id","py->cpp"},{"priority","critical"}}}}}});
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",2},{"method","tools/call"},{"params",{{"name","whetstone_get_upgrade_queue"},{"arguments",nlohmann::json::object()}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res["total_active"].get<int>()==1,"one");P();}
void t6(){T(sorted_by_priority);
MCPServer srv;
srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id","py->cpp"},{"priority","experimental"}}}}}});
srv.handleRequest({{"jsonrpc","2.0"},{"id",2},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id","rust->go"},{"priority","critical"}}}}}});
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",3},{"method","tools/call"},{"params",{{"name","whetstone_get_upgrade_queue"},{"arguments",nlohmann::json::object()}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res["entries"][0]["priority"]=="critical","sorted");P();}
void t7(){T(shown_field);
MCPServer srv;
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",1},{"method","tools/call"},{"params",{{"name","whetstone_get_upgrade_queue"},{"arguments",nlohmann::json::object()}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res.contains("shown"),"shown");P();}
void t8(){T(limit_respected);
MCPServer srv;
for(int i=0;i<3;++i){
std::string pid="pair"+std::to_string(i);
srv.handleRequest({{"jsonrpc","2.0"},{"id",i},{"method","tools/call"},{"params",{{"name","whetstone_enqueue_pair_upgrade"},{"arguments",{{"pair_id",pid},{"priority","coverage"}}}}}});
}
auto r=srv.handleRequest({{"jsonrpc","2.0"},{"id",10},{"method","tools/call"},{"params",{{"name","whetstone_get_upgrade_queue"},{"arguments",{{"limit",2}}}}}});
auto res=nlohmann::json::parse(r["result"]["content"][0]["text"].get<std::string>());
C(res["shown"].get<int>()==2,"limit");P();}
int main(){
std::cout<<"Step 886: whetstone_get_upgrade_queue\n";
t1();t2();t3();t4();t5();t6();t7();t8();
std::cout<<"\nResults: "<<p<<"/"<<(p+f)<<" passed\n";
return f?1:0;
}

View File

@@ -0,0 +1,41 @@
// Step 887: Upgrade queue observability panel model (8 tests)
#include "graduation/UpgradeQueueObservabilityPanel.h"
#include <iostream>
static int p=0,f=0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){T(snapshot_id_set);
auto s=UpgradeQueueObservabilityPanel::snapshot("snap-1",10,5,1,4,0.8f);
C(s.snapshotId=="snap-1","id");P();}
void t2(){T(healthy_label);
auto s=UpgradeQueueObservabilityPanel::snapshot("s",10,5,0,5,0.9f);
C(s.healthLabel=="healthy","healthy");P();}
void t3(){T(degraded_label);
auto s=UpgradeQueueObservabilityPanel::snapshot("s",10,5,1,4,0.5f);
C(s.healthLabel=="degraded","degraded");P();}
void t4(){T(critical_label);
auto s=UpgradeQueueObservabilityPanel::snapshot("s",10,5,2,3,0.2f);
C(s.healthLabel=="critical","critical");P();}
void t5(){T(queued_stored);
auto s=UpgradeQueueObservabilityPanel::snapshot("s",15,5,1,9,0.8f);
C(s.totalQueued==15,"queued");P();}
void t6(){T(completed_stored);
auto s=UpgradeQueueObservabilityPanel::snapshot("s",10,5,1,4,0.8f);
C(s.totalCompleted==4,"completed");P();}
void t7(){T(health_score_stored);
auto s=UpgradeQueueObservabilityPanel::snapshot("s",10,5,1,4,0.75f);
C(s.healthScore==0.75f,"score");P();}
void t8(){T(to_json_has_health_label);
auto s=UpgradeQueueObservabilityPanel::snapshot("s",10,5,0,5,0.9f);
auto j=UpgradeQueueObservabilityPanel::toJson(s);
C(j.contains("health_label"),"json");P();}
int main(){
std::cout<<"Step 887: Upgrade queue observability panel\n";
t1();t2();t3();t4();t5();t6();t7();t8();
std::cout<<"\nResults: "<<p<<"/"<<(p+f)<<" passed\n";
return f?1:0;
}

View File

@@ -0,0 +1,24 @@
// Step 888: Sprint65IntegrationSummary tests (8 tests)
#include "Sprint65IntegrationSummary.h"
#include <iostream>
static int p=0,f=0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c,m) if(!(c)){F(m);return;}
void t1(){T(sprintNumber);C(Sprint65IntegrationSummary::sprintNumber==65,"65");P();}
void t2(){T(stepsCompleted);C(Sprint65IntegrationSummary::stepsCompleted==10,"10");P();}
void t3(){T(theme_not_empty);C(std::string(Sprint65IntegrationSummary::theme).size()>0,"theme");P();}
void t4(){T(verify_true);C(Sprint65IntegrationSummary::verify(),"verify");P();}
void t5(){T(json_has_sprint_key);auto j=Sprint65IntegrationSummary::toJson();C(j.contains("sprint"),"sprint");P();}
void t6(){T(json_sprint_65);auto j=Sprint65IntegrationSummary::toJson();C(j["sprint"]==65,"sprint=65");P();}
void t7(){T(json_steps_10);auto j=Sprint65IntegrationSummary::toJson();C(j["steps"]==10,"steps=10");P();}
void t8(){T(json_status_complete);auto j=Sprint65IntegrationSummary::toJson();C(j["status"]=="complete","complete");P();}
int main(){
std::cout<<"Step 888: Sprint65IntegrationSummary\n";
t1();t2();t3();t4();t5();t6();t7();t8();
std::cout<<"\nResults: "<<p<<"/"<<(p+f)<<" passed\n";
return f?1:0;
}