diff --git a/experiments/shell/local_shell_diagnostics.hpp b/experiments/shell/local_shell_diagnostics.hpp index 3b05e137..5b9e61ea 100644 --- a/experiments/shell/local_shell_diagnostics.hpp +++ b/experiments/shell/local_shell_diagnostics.hpp @@ -31,4 +31,16 @@ inline void local_shell_progress(const std::filesystem::path& directory, std::st raw.close(); require(bool(raw), "local shell private output write failed"); } } +inline void local_shell_size_readiness(const std::filesystem::path& directory, std::string_view role, + unsigned long columns, unsigned long rows, bool settled, + bool marker_present, unsigned long observed_bytes) { + require(role=="cmd" || role=="powershell" || role=="pwsh" || role=="wsl", "invalid local shell diagnostic role"); + std::ofstream progress(directory/"shells-size-readiness.jsonl",std::ios::binary|std::ios::app); + progress<<"{\"schema\":\"termforge-local-shell-size-readiness-v1\",\"role\":\""<checkpoint()) { require(captured()==evidence.baseline(),"clipboard receiver baseline differs"); evidence.receiver->release(); + // Setup writes are not the product behaviour under test; Explorer or a + // previous case can hold the desktop clipboard for a moment, so give the + // fixture a small bounded retry instead of failing the whole scenario. + auto prepare_clipboard = [&](auto&& write) { + std::string last; + for (int attempt = 0; attempt < 4; ++attempt) { + try { write(); return; } catch (const std::exception& error) { last = error.what(); } + if (attempt + 1 != 4) Sleep(50 * (attempt + 1)); + } + throw std::runtime_error(last); + }; try { if(evidence.index==0) { - tf_shell::write_unicode_clipboard(window_,u"OCCUPIED_MUST_NOT_SEND"); + prepare_clipboard([&] { tf_shell::write_unicode_clipboard(window_,u"OCCUPIED_MUST_NOT_SEND"); }); evidence.owner=std::make_unique(false); - } else if(evidence.index==1) tf_shell_test::write_oversized_clipboard(window_); + } else if(evidence.index==1) prepare_clipboard([&] { tf_shell_test::write_oversized_clipboard(window_); }); else evidence.owner=std::make_unique(true); } catch(const std::exception& error) { throw std::runtime_error(std::string("clipboard case=")+evidence.name()+ diff --git a/experiments/shell/workspace_shells_scenario.hpp b/experiments/shell/workspace_shells_scenario.hpp index 12e54bad..041f298f 100644 --- a/experiments/shell/workspace_shells_scenario.hpp +++ b/experiments/shell/workspace_shells_scenario.hpp @@ -11,6 +11,18 @@ inline void Workspace::scenario_shells() { selected(Group::main)->render_to(frame.dc, main.left, main.top); selected(Group::bottom)->render_to(frame.dc, bottom.left, bottom.top); frame.save(image_); + // #80: which readiness condition was actually missing when the deadline hit. + const auto diagnostic_directory = std::filesystem::path(image_).parent_path(); + for (const auto group : {Group::bottom, Group::main}) for (auto& tab : group_tabs(group)) { + if (!tab.launch) continue; + const auto [columns, rows] = tab.shell->grid_dimensions(); + const std::string role(tab.launch->kind.begin(), tab.launch->kind.end()); + tf_shell_test::local_shell_size_readiness( + diagnostic_directory, role, static_cast(columns), static_cast(rows), + tab.shell->settled(), + tab.shell->contains_line("TF_SIZE_" + std::to_string(columns) + "x" + std::to_string(rows)), + static_cast(tab.shell->observed_output().size())); + } require(false, ("workspace shells scenario timeout at stage " + std::to_string(stage_)).c_str()); } const auto directory = std::filesystem::path(image_).parent_path();