diff --git a/scripts/src/hwlab-node-web-observe-analyzer-project-source.ts b/scripts/src/hwlab-node-web-observe-analyzer-project-source.ts index 878ce9fb..edaf642e 100644 --- a/scripts/src/hwlab-node-web-observe-analyzer-project-source.ts +++ b/scripts/src/hwlab-node-web-observe-analyzer-project-source.ts @@ -410,8 +410,12 @@ function projectManagementPaneGapRows(projectSamples) { const maxGapPx = maxNumber(severeGaps.map((item) => item.bottomGapPx)); const maxGapRatio = maxNumber(severeGaps.map((item) => item.bottomGapRatio)); const multiPane = severeGaps.length >= 2; - const singleExtreme = maxGapPx >= 240 && maxGapRatio >= 0.45; - if (!multiPane && !singleExtreme) continue; + const singlePrimaryPaneExtreme = severeGaps.some((item) => + item.name !== "task-tree" + && Number(item.bottomGapPx ?? 0) >= 240 + && Number(item.bottomGapRatio ?? 0) >= 0.45 + ); + if (!multiPane && !singlePrimaryPaneExtreme) continue; const selectedTaskRefHash = sample?.projectManagement?.selectedTaskRef?.hash ?? null; const isMdtodo = sample?.projectManagement?.pageKind === "project-management-mdtodo"; const isInitialEmptyDetail = isMdtodo && !selectedTaskRefHash; diff --git a/scripts/src/hwlab-node-web-observe-runner-sampling-source.test.ts b/scripts/src/hwlab-node-web-observe-runner-sampling-source.test.ts index 229028d2..c72f3596 100644 --- a/scripts/src/hwlab-node-web-observe-runner-sampling-source.test.ts +++ b/scripts/src/hwlab-node-web-observe-runner-sampling-source.test.ts @@ -5,6 +5,7 @@ import { MDTODO_TASK_TREE_PANE_CONTENT_SELECTOR, nodeWebObserveRunnerSamplingSource, } from "./hwlab-node-web-observe-runner-sampling-source"; +import { nodeWebObserveAnalyzerProjectSource } from "./hwlab-node-web-observe-analyzer-project-source"; test("MDTODO task tree pane gap treats the pinned facts footer as content", async () => { assert.match( @@ -47,3 +48,48 @@ test("MDTODO task tree pane gap treats the pinned facts footer as content", asyn ]); assert.equal(exitCode, 0, stderr); }); + +test("MDTODO pane gap ignores a naturally short task tree but keeps primary pane regressions", () => { + const projectManagementPaneGapRows = new Function( + "maxNumber", + "projectManagementSampleRef", + `${nodeWebObserveAnalyzerProjectSource()}; return projectManagementPaneGapRows;`, + )( + (values: unknown[]) => Math.max(0, ...values.map((value) => Number(value ?? 0))), + (sample: Record) => ({ seq: sample.seq ?? null }), + ) as (samples: unknown[]) => { actionable: unknown[]; ignored: unknown[] }; + + const pane = (name: string, bottomGapPx: number, bottomGapRatio: number) => ({ + name, + visible: true, + widthPx: 300, + heightPx: 600, + bottomGapPx, + bottomGapRatio, + contentNodeCount: 4, + }); + const sample = (paneGaps: unknown[]) => ({ + seq: 1, + projectManagement: { + pageKind: "project-management-mdtodo", + selectedTaskRef: { hash: "sha256:opaque" }, + paneGaps, + }, + }); + + assert.deepEqual( + projectManagementPaneGapRows([sample([pane("task-tree", 391, 0.618)])]), + { actionable: [], ignored: [], valuesRedacted: true }, + ); + assert.equal( + projectManagementPaneGapRows([sample([pane("task-detail", 391, 0.618)])]).actionable.length, + 1, + ); + assert.equal( + projectManagementPaneGapRows([sample([ + pane("task-tree", 240, 0.4), + pane("task-detail", 180, 0.3), + ])]).actionable.length, + 1, + ); +});