feat(editor): add --summary flag to --audit-watertight

CI-friendly one-line rollup mode for the welded watertight
audit. Replaces the per-mesh PASS/FAIL detail lines with a
single status line:

  watertight: FAIL (121 meshes, 27 failure(s)) [/tmp/migtest, weld 0.001000]
  watertight: PASS (6 meshes, 0 failure(s)) [/tmp/camp, weld 0.001000]

Format: "watertight: <PASS|FAIL> (<N> meshes, <K> failure(s))
[<root>, weld <eps>]". Exit code unchanged — failure count
capped at 255, matching the verbose-mode contract.

Useful for build dashboards / CI grep lines / Slack-bot
notifications where the full per-mesh dump would be too
noisy. Verbose mode is still the default; opt in with
--summary.
This commit is contained in:
Kelsi 2026-05-09 13:09:28 -07:00
parent 8d75dd3867
commit 88ba27f9ea
2 changed files with 15 additions and 2 deletions

View file

@ -354,10 +354,13 @@ int handleAuditWatertight(int& i, int argc, char** argv) {
// CI-friendly: zero on full success.
std::string root = argv[++i];
bool jsonOut = false;
bool summary = false;
float weldEps = 1e-4f;
while (i + 1 < argc && argv[i + 1][0] == '-') {
if (std::strcmp(argv[i + 1], "--json") == 0) {
jsonOut = true; ++i;
} else if (std::strcmp(argv[i + 1], "--summary") == 0) {
summary = true; ++i;
} else if (std::strcmp(argv[i + 1], "--weld") == 0 && i + 2 < argc) {
try { weldEps = std::stof(argv[i + 2]); } catch (...) {}
i += 2;
@ -414,6 +417,16 @@ int handleAuditWatertight(int& i, int argc, char** argv) {
std::printf("%s\n", j.dump(2).c_str());
return std::min(failCount, 255);
}
if (summary) {
// Single rollup line for CI dashboards: PASS/FAIL +
// counts. Goes to stdout so build systems can capture it.
std::printf("watertight: %s (%zu meshes, %d failure(s)) "
"[%s, weld %.6f]\n",
failCount == 0 ? "PASS" : "FAIL",
rows.size(), failCount,
root.c_str(), weldEps);
return std::min(failCount, 255);
}
std::printf("Watertight audit: %s (weld eps %.6f)\n",
root.c_str(), weldEps);
if (rows.empty()) {

View file

@ -589,8 +589,8 @@ void printUsage(const char* argv0) {
std::printf(" Convert a multi-group WOB building into a single WOC collision file (weld is per-group)\n");
std::printf(" --bake-zone-collision <zoneDir> [out.woc] [--weld <eps>] [--steep <deg>]\n");
std::printf(" Walk every .wom + .wob under zoneDir, weld each independently, append to one shared WOC\n");
std::printf(" --audit-watertight <zoneDir|projectDir> [--weld <eps>] [--json]\n");
std::printf(" Walk every .wom under root, run welded watertight check; exit code = failure count (CI-friendly)\n");
std::printf(" --audit-watertight <zoneDir|projectDir> [--weld <eps>] [--json] [--summary]\n");
std::printf(" Walk every .wom under root, run welded watertight check; --summary prints a one-line rollup\n");
std::printf(" --audit-watertight-wob <zoneDir|projectDir> [--weld <eps>] [--json]\n");
std::printf(" Walk every .wob, check that EVERY group is closed (per-group weld) — interior rooms must be solid\n");
std::printf(" --import-obj <obj-path> [wom-base]\n");