Files
houseplan-card/test/fixtures/smoke-select/741-call-arguments.diff
T
Claudeandclaude[bot] d8e09cd1a0 test(harness): close three smoke-select and fixture blind spots (#754)
Three independent blind spots in the test harness.

1. smoke-select read symbols only from changed lines of a --unified=0
   diff. An edit to the arguments of a multi-line call names nothing:
   #741 (d5bdfde9) changed only the arguments of
   runtime.resolveIsoOverlayFitEnvelope({ on the line above, and the
   selection answered "unproven" plus the visual minimum, although the
   callee is registered in smoke-links for smoke_iso_flat_parity and
   smoke_isometric_contract - the two smokes the #741 author ran by hand.
   The selection diff now carries CALL_CONTEXT_LINES = 3 lines of
   context; for each changed line parseDiff looks for the nearest
   unclosed "(" above it within the hunk, walking through a literal
   argument ({ or [ after "(", "," or "["), stopping at ";" on depth zero
   or any other unclosed brace. A callee from the symbol table joins
   symbols and the new callees field and is marked "(вызов)" in the
   report. Context lines never give direct symbols. task-packet takes a
   separate context diff for selectSmokes; change-risk keeps --unified=0.
   Over the last 80 src commits of dev: 16 commits gain a callee, 2 move
   from unproven to a proven link (#741, #724 5f8e8ca7), +15 smokes in
   total, at most 4 per commit, none lost.

2. The #732 dead-field check judged only scene-builder calls. The four
   resolveIsoOverlayFitEnvelope({...}) literals in iso-scene-render tests
   went straight into the test-build function, so stageSize: null (the
   field #741 removed) stayed green. They now go through overlayFit typed
   with OverlayFitFixture (keys of IsoOverlayFitEnvelopeInput); the check
   judges overlayFit/resolveIsoOverlayFitEnvelope calls like the scene
   builders, and its probe asserts that OverlayFitFixture rejects
   stageSize, so the type resolved to the real input and not to any.

3. smoke_backdrop's mode() called the private _setMode and slept 220 ms.
   It now enters a mode through __hpTest.setMode and waits for the end of
   the transition by the same markers as section 6b (#715): one page
   helper used by both. Oracles and the 59 check names are unchanged.

Witnesses: d5bdfde9 selects both iso smokes with no "unproven"; the same
fixture without context lines is unproven again; attribution disabled
reds both AC1 units. stageSize: null in an overlayFit call reds the first
#732 test; a direct resolveIsoOverlayFitEnvelope({...}) reds the third.
smoke_backdrop is green normally and with animation frames slowed to 60
and 150 ms; a stage animation that never ends fails with a named error.

Issue: #754
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-10-01 12:24:59 +00:00

111 lines
5.9 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
commit d5bdfde9196bc7ecf7a4cfefea04f4dd69559b0d
Author: Claude <noreply@anthropic.com>
Date: Thu Oct 1 08:25:09 2026 +0300
refactor(iso): drop the unused stageSize from the overlay fit input (#741)
Since #713 the overlay fit envelope reserves no nudge budget, and since
#725 _isoScene passes `stageSize: null` while resolveIsoOverlayFitEnvelope
never reads the field. The room focus still built a { width, height }
object from the stage for nothing. The optional field is removed from
IsoOverlayFitEnvelopeInput together with both call-site arguments.
The #725 AC3 unit compared bounds with stageSize null and 1000x500, which
is now meaningless; it checks instead that the fit bounds follow only
scene.frame and the tiles: the same bounds for every stage aspect, a moved
frame moves them, an enclosing frame is returned as is.
Issue: #741
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
diff --git a/src/houseplan-card.ts b/src/houseplan-card.ts
index b1421819..4ccce6a5 100755
--- a/src/houseplan-card.ts
+++ b/src/houseplan-card.ts
@@ -6004,7 +6004,7 @@ export class HouseplanCard extends LitElement {
disp, runtime.resolveIsoDecorationLayers(disp), scene, iconPct, effectiveDeviceBaseSize(iconPct),
disp.showLqi ?? this._config?.show_signal ?? true);
const envelope = overlays && runtime.resolveIsoOverlayFitEnvelope({
- baseBounds: scene.frame, entries: overlays.entries, stageSize: null, targetView: (bounds) =>
+ baseBounds: scene.frame, entries: overlays.entries, targetView: (bounds) =>
fitView([bounds.x, bounds.y, bounds.w, bounds.h], aspect) });
return envelope ? { ...scene, frame: envelope.bounds, overlayFitEntries: overlays.entries } : scene;
}
@@ -6192,8 +6192,7 @@ export class HouseplanCard extends LitElement {
const runtime = this._isoSceneRuntime, entries = this._renderIsoScene?.overlayFitEntries;
if (target && this._effectiveProjection() === 'iso' && runtime && entries?.length) {
const envelope = runtime.resolveIsoOverlayFitEnvelope({
- baseBounds: bounds, entries, ownerId: room.id, stageSize: {
- width: stage.clientWidth, height: stage.clientHeight },
+ baseBounds: bounds, entries, ownerId: room.id,
targetView: (fitBounds) => targetOf(fitBounds)?.viewBox ?? null });
if (envelope) { bounds = envelope.bounds; target = targetOf(bounds); }
}
diff --git a/src/iso-scene-render.ts b/src/iso-scene-render.ts
index cf61222b..a617fbb6 100644
--- a/src/iso-scene-render.ts
+++ b/src/iso-scene-render.ts
@@ -648,7 +648,6 @@ export function isoOverlaySceneBounds(
export interface IsoOverlayFitEnvelopeInput {
baseBounds: Rect;
entries: readonly IsoOverlayRenderEntry[];
- stageSize?: { width: number; height: number } | null;
targetView(bounds: Rect): Rect | null;
ownerId?: string;
}
diff --git a/test/iso-scene-render.test.mjs b/test/iso-scene-render.test.mjs
index e514aa8f..eecd468f 100644
--- a/test/iso-scene-render.test.mjs
+++ b/test/iso-scene-render.test.mjs
@@ -195,7 +195,7 @@ test('#713 K8: overlay fit is the structure plus visible tiles, no #651 nudge re
assert.deepEqual(otherRoom.bounds, { x: 0, y: 0, w: 100, h: 100 });
});
-test('#725 AC3: the overlay fit frame does not depend on the stage aspect or size', () => {
+test('#725 AC3/#741: the overlay fit bounds depend only on scene.frame and the tiles, never on the stage', () => {
/** @type {OverlayEntryFixture[]} */
const entries = [
{
@@ -213,25 +213,25 @@ test('#725 AC3: the overlay fit frame does not depend on the stage aspect or siz
},
},
];
- const baseBounds = { x: 0, y: 0, w: 100, h: 100 };
+ const frame = { x: 0, y: 0, w: 100, h: 100 };
// The card's targetView: a contain-fit of the frame at the stage aspect.
const fitAt = (aspect) => (bounds) => fitView([bounds.x, bounds.y, bounds.w, bounds.h], aspect);
- const results = [];
- for (const aspect of [0.5, 2]) {
- for (const stageSize of [null, { width: 1000, height: 500 }]) {
- const fitted = resolveIsoOverlayFitEnvelope({ baseBounds, entries, stageSize, targetView: fitAt(aspect) });
- assert.ok(fitted, `aspect ${aspect}, stage ${JSON.stringify(stageSize)}: an envelope`);
- results.push(fitted);
- }
- }
+ const fit = (baseBounds, aspect) => resolveIsoOverlayFitEnvelope({ baseBounds, entries, targetView: fitAt(aspect) });
+ // Portrait, square, a 1000×500 and a 320×180 stage, the frame's own aspect (`_isoScene`).
+ const aspects = [0.5, 1, 1000 / 500, 320 / 180, frame.w / frame.h];
+ const results = aspects.map((aspect) => {
+ const fitted = fit(frame, aspect);
+ assert.ok(fitted, `aspect ${aspect}: an envelope`);
+ assert.deepEqual(fitted.view, fitAt(aspect)(fitted.bounds), `aspect ${aspect}: the view fits the bounds`);
+ return fitted;
+ });
assert.deepEqual(results[0].bounds, { x: 0, y: 0, w: 105, h: 110 }, 'the structure plus both tiles');
for (const fitted of results) assert.deepEqual(fitted.bounds, results[0].bounds);
assert.notDeepEqual(results[0].view, results[2].view, 'only the view follows the aspect');
- // `_isoScene` passes the frame's own aspect: any positive finite value gives the same bounds.
- const ownAspect = resolveIsoOverlayFitEnvelope({
- baseBounds, entries, stageSize: null, targetView: fitAt(baseBounds.w / baseBounds.h),
- });
- assert.deepEqual(ownAspect.bounds, results[0].bounds);
+ // The bounds follow scene.frame: a moved frame moves them, an enclosing frame is the answer as is.
+ assert.deepEqual(fit({ x: 50, y: 0, w: 100, h: 100 }, 2).bounds, { x: 34, y: 0, w: 116, h: 110 });
+ const enclosing = { x: -50, y: -50, w: 300, h: 300 };
+ for (const aspect of aspects) assert.deepEqual(fit(enclosing, aspect).bounds, enclosing);
});
test('one painter queue paints a nearer wall after an unrelated rear opening', () => {