fix: topology array reordering by subject order + unary inStackingContext
Topology array order mismatch (critical bug): - CDP browser script iterates elements in document order (querySelectorAll), but solver accesses topology arrays by selector-resolution order. - Fix: add subjectIds array to TopologyRecord tracking the backendNodeId at each document-order position; remapTopologyIds now reorders all 6 topology arrays before remapping backendNodeIds to solver IDs. - Fallback: when subjectIds is missing (cached pre-fix data), falls back to simple remap without reordering. Unary inStackingContext compilation: - compileCanonicalClauseToFormula treated inStackingContext as always binary, creating referenceBinding with undefined selector for unary assertions. - Fix: add (inStackingContext && !clause.reference) to unaryPredicate/isUnary. Hard test fixture (fixtures package): - 29-element geometric fixture with 10 scenarios - 57 assertions (54 spatial + 3 topology) all pass end-to-end
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Imhotep Hard Geometric Fixture</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #1a1a2e; color: #e0e0e0; font-family: monospace; padding: 20px; }
|
||||
.legend { margin-bottom: 16px; font-size: 13px; line-height: 1.6; }
|
||||
.legend strong { color: #ffcc00; }
|
||||
|
||||
/* 1. TRANSFORMS */
|
||||
.transform-container {
|
||||
position: absolute; left: 30px; top: 80px; width: 220px; height: 160px;
|
||||
background: rgba(100,100,255,0.15); border: 2px dashed #6666ff;
|
||||
transform: rotate(15deg) scale(1.5); transform-origin: top left;
|
||||
}
|
||||
.rotated-box-a { position: absolute; left: 10px; top: 10px; width: 60px; height: 40px; background: #ff6b6b; border: 2px solid #ff4444; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #fff; }
|
||||
.rotated-box-b { position: absolute; left: 120px; top: 80px; width: 60px; height: 40px; background: #51cf66; border: 2px solid #2f9e44; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #fff; }
|
||||
|
||||
/* 2. SCROLL CLIP */
|
||||
.scroll-clip-container { position: absolute; left: 400px; top: 80px; width: 200px; height: 200px; overflow: hidden; background: rgba(255,200,100,0.1); border: 2px solid #ffa500; }
|
||||
.clipped-child { width: 80px; height: 80px; background: #ff6b6b; border: 1px solid #fff; margin: 10px; }
|
||||
.overflown-child { width: 50px; height: 250px; background: linear-gradient(to bottom, #ffa500, #ffd43b); border: 1px solid #fff; margin: 10px; }
|
||||
|
||||
/* 3. NESTED POSITIONING */
|
||||
.relative-container { position: absolute; left: 30px; top: 320px; width: 250px; height: 180px; background: rgba(150,100,255,0.12); border: 2px dashed #9c36b5; contain: paint; }
|
||||
.absolute-child { position: absolute; left: 20px; top: 15px; width: 180px; height: 120px; background: rgba(255,150,255,0.2); border: 2px solid #cc5de8; }
|
||||
.fixed-nested-child { position: fixed; left: 70px; top: 355px; width: 60px; height: 50px; background: #20c997; border: 2px solid #099268; display: flex; align-items: center; justify-content: center; font-size: 9px; color: #fff; z-index: 10; }
|
||||
|
||||
/* 4. OVERLAPPING Z-INDEX */
|
||||
.z-box { position: absolute; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #fff; font-weight: bold; }
|
||||
.z1-box { left: 400px; top: 320px; width: 130px; height: 130px; background: rgba(255,107,107,0.7); border: 2px solid #ff4444; z-index: 1; }
|
||||
.z2-box { left: 430px; top: 350px; width: 130px; height: 130px; background: rgba(81,207,102,0.7); border: 2px solid #2f9e44; z-index: 2; }
|
||||
.z3-box { left: 460px; top: 380px; width: 130px; height: 130px; background: rgba(74,144,226,0.7); border: 2px solid #2266cc; z-index: 3; }
|
||||
|
||||
/* 5. ZERO-SIZE / HIDDEN */
|
||||
.zero-size-box { position: absolute; left: 30px; top: 570px; width: 0; height: 0; background: #ff0000; border: 1px solid #ff0000; }
|
||||
.display-none-box { position: absolute; left: 100px; top: 570px; width: 60px; height: 40px; background: #ffa500; border: 2px solid #ff8c00; display: none; }
|
||||
.visibility-hidden-box { position: absolute; left: 180px; top: 570px; width: 60px; height: 40px; background: #ffd43b; border: 2px solid #fab005; visibility: hidden; }
|
||||
.opacity-zero-box { position: absolute; left: 260px; top: 570px; width: 60px; height: 40px; background: #51cf66; border: 2px solid #2f9e44; opacity: 0; }
|
||||
|
||||
/* 6. FLEXBOX GAP */
|
||||
.flex-container { position: absolute; left: 30px; top: 660px; display: flex; gap: 20px; width: 440px; height: 80px; background: rgba(100,200,255,0.1); border: 2px dashed #4a90e2; padding: 10px; }
|
||||
.flex-item { width: 80px; height: 60px; display: flex; align-items: center; justify-content: center; font-size: 13px; color: #fff; font-weight: bold; border: 2px solid; }
|
||||
.flex-item-1 { background: #ff6b6b; border-color: #ff4444; }
|
||||
.flex-item-2 { background: #51cf66; border-color: #2f9e44; }
|
||||
.flex-item-3 { background: #4a90e2; border-color: #2266cc; }
|
||||
|
||||
/* 7. BORDER / PADDING */
|
||||
.border-box-el { position: absolute; left: 30px; top: 800px; width: 140px; height: 100px; background: #fab005; border: 12px solid #e67700; padding: 20px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #1a1a2e; font-weight: bold; }
|
||||
|
||||
/* 8. ALIGNMENT EDGES */
|
||||
.alignment-reference { position: absolute; left: 250px; top: 800px; width: 100px; height: 100px; background: rgba(200,200,200,0.15); border: 2px dashed #aaa; display: flex; align-items: center; justify-content: center; font-size: 10px; }
|
||||
.left-aligned { position: absolute; left: 250px; top: 930px; width: 40px; height: 30px; background: #ff6b6b; border: 2px solid #ff4444; display: flex; align-items: center; justify-content: center; font-size: 8px; color: #fff; }
|
||||
.right-aligned { position: absolute; left: 310px; top: 930px; width: 40px; height: 30px; background: #51cf66; border: 2px solid #2f9e44; display: flex; align-items: center; justify-content: center; font-size: 8px; color: #fff; }
|
||||
.top-aligned { position: absolute; left: 380px; top: 800px; width: 30px; height: 40px; background: #4a90e2; border: 2px solid #2266cc; display: flex; align-items: center; justify-content: center; font-size: 8px; color: #fff; }
|
||||
.bottom-aligned { position: absolute; left: 380px; top: 860px; width: 30px; height: 40px; background: #fab005; border: 2px solid #e67700; display: flex; align-items: center; justify-content: center; font-size: 8px; color: #1a1a2e; }
|
||||
|
||||
/* 9. DIAGONAL SEPARATION */
|
||||
.diagonal-top-left { position: absolute; left: 480px; top: 640px; width: 60px; height: 40px; background: #e599f7; border: 2px solid #ae3ec9; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #1a1a2e; }
|
||||
.diagonal-bottom-right { position: absolute; left: 620px; top: 800px; width: 60px; height: 40px; background: #63e6be; border: 2px solid #099268; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #1a1a2e; }
|
||||
|
||||
/* 10. ADJACENT / TOUCHING / CENTERED */
|
||||
.adjacent-a { position: absolute; left: 600px; top: 860px; width: 50px; height: 50px; background: #ff922b; border: 2px solid #e67700; display: flex; align-items: center; justify-content: center; font-size: 9px; color: #fff; }
|
||||
.adjacent-b { position: absolute; left: 650px; top: 860px; width: 50px; height: 50px; background: #ff6b6b; border: 2px solid #ff4444; display: flex; align-items: center; justify-content: center; font-size: 9px; color: #fff; }
|
||||
.center-container { position: absolute; left: 700px; top: 640px; width: 160px; height: 160px; background: rgba(255,255,255,0.05); border: 2px dashed #888; display: flex; align-items: center; justify-content: center; }
|
||||
.center-child { width: 40px; height: 40px; background: #fab005; border: 2px solid #e67700; }
|
||||
|
||||
.scene-label { position: absolute; font-size: 11px; color: #888; pointer-events: none; white-space: nowrap; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="legend">
|
||||
<strong>Imhotep Hard Geometric Fixture</strong><br>
|
||||
Open DevTools Console to see bounding rects of all <code>data-testid</code> elements.<br>
|
||||
All elements are absolutely positioned for deterministic layout.
|
||||
</div>
|
||||
|
||||
<!-- 1. TRANSFORMS -->
|
||||
<div class="scene-label" style="left:30px;top:60px;">1. TRANSFORM (rotate 15deg + scale 1.5)</div>
|
||||
<div class="transform-container" data-testid="transform-container">
|
||||
<div class="rotated-box-a" data-testid="rotated-box-a">A</div>
|
||||
<div class="rotated-box-b" data-testid="rotated-box-b">B</div>
|
||||
</div>
|
||||
|
||||
<!-- 2. SCROLL CLIP -->
|
||||
<div class="scene-label" style="left:400px;top:60px;">2. overflown-childChild 50x250 in 200x200 container</div>
|
||||
<div class="scroll-clip-container" data-testid="scroll-clip-container">
|
||||
<div class="clipped-child" data-testid="clipped-child"></div>
|
||||
<div class="overflown-child" data-testid="overflown-child"></div>
|
||||
</div>
|
||||
|
||||
<!-- 3. NESTED POSITIONING -->
|
||||
<div class="scene-label" style="left:30px;top:300px;">3. NESTED (relative > absolute > fixed, contain:paint)</div>
|
||||
<div class="relative-container" data-testid="relative-container">
|
||||
<div class="absolute-child" data-testid="absolute-child">
|
||||
<div class="fixed-nested-child" data-testid="fixed-nested-child">fixed</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 4. OVERLAPPING Z-INDEX -->
|
||||
<div class="scene-label" style="left:400px;top:300px;">4. OVERLAPPING Z-INDEX (z:1,2,3)</div>
|
||||
<div class="z-box z1-box" data-testid="z1-box">z=1</div>
|
||||
<div class="z-box z2-box" data-testid="z2-box">z=2</div>
|
||||
<div class="z-box z3-box" data-testid="z3-box">z=3</div>
|
||||
|
||||
<!-- 5. ZERO-SIZE / HIDDEN -->
|
||||
<div class="scene-label" style="left:30px;top:550px;">5. ZERO-SIZE / HIDDEN</div>
|
||||
<div class="zero-size-box" data-testid="zero-size-box"></div>
|
||||
<div class="display-none-box" data-testid="display-none-box">none</div>
|
||||
<div class="visibility-hidden-box" data-testid="visibility-hidden-box">hidden</div>
|
||||
<div class="opacity-zero-box" data-testid="opacity-zero-box">opacity:0</div>
|
||||
|
||||
<!-- 6. FLEXBOX GAP -->
|
||||
<div class="scene-label" style="left:30px;top:638px;">6. FLEXBOX GAP (gap:20px)</div>
|
||||
<div class="flex-container" data-testid="flex-container">
|
||||
<div class="flex-item flex-item-1" data-testid="flex-item-1">1</div>
|
||||
<div class="flex-item flex-item-2" data-testid="flex-item-2">2</div>
|
||||
<div class="flex-item flex-item-3" data-testid="flex-item-3">3</div>
|
||||
</div>
|
||||
|
||||
<!-- 7. BORDER / PADDING -->
|
||||
<div class="scene-label" style="left:30px;top:780px;">7. BORDER (12px) + PADDING (20px) border-box</div>
|
||||
<div class="border-box-el" data-testid="border-box-el">border-box</div>
|
||||
|
||||
<!-- 8. ALIGNMENT EDGES -->
|
||||
<div class="scene-label" style="left:250px;top:780px;">8. EDGE ALIGNMENT</div>
|
||||
<div class="alignment-reference" data-testid="alignment-reference">ref</div>
|
||||
<div class="left-aligned" data-testid="left-aligned">L</div>
|
||||
<div class="right-aligned" data-testid="right-aligned">R</div>
|
||||
<div class="top-aligned" data-testid="top-aligned">T</div>
|
||||
<div class="bottom-aligned" data-testid="bottom-aligned">B</div>
|
||||
|
||||
<!-- 9. DIAGONAL SEPARATION -->
|
||||
<div class="scene-label" style="left:480px;top:622px;">9. DIAGONAL SEPARATION</div>
|
||||
<div class="diagonal-top-left" data-testid="diagonal-top-left">TL</div>
|
||||
<div class="diagonal-bottom-right" data-testid="diagonal-bottom-right">BR</div>
|
||||
|
||||
<!-- 10. ADJACENT / TOUCHING / CENTERED -->
|
||||
<div class="scene-label" style="left:600px;top:842px;">10. ADJACENT pair (edge touch)</div>
|
||||
<div class="adjacent-a" data-testid="adjacent-a">A</div>
|
||||
<div class="adjacent-b" data-testid="adjacent-b">B</div>
|
||||
<div class="scene-label" style="left:700px;top:620px;">CENTERED child</div>
|
||||
<div class="center-container" data-testid="center-container">
|
||||
<div class="center-child" data-testid="center-child"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var elements = document.querySelectorAll('[data-testid]');
|
||||
console.group('Imhotep Hard Fixture — Bounding Rects');
|
||||
console.log('Element count with data-testid:', elements.length);
|
||||
elements.forEach(function (el) {
|
||||
var testid = el.getAttribute('data-testid');
|
||||
var rect = el.getBoundingClientRect();
|
||||
var cs = window.getComputedStyle(el);
|
||||
console.log(
|
||||
'%c' + testid + '%c ' +
|
||||
JSON.stringify({ x: rect.left.toFixed(1), y: rect.top.toFixed(1), w: rect.width.toFixed(1), h: rect.height.toFixed(1), display: cs.display, visibility: cs.visibility, opacity: cs.opacity }),
|
||||
'color: #ffcc00; font-weight: bold;', 'color: #aaa;'
|
||||
);
|
||||
});
|
||||
console.groupEnd();
|
||||
})();
|
||||
</script></body></html>
|
||||
Reference in New Issue
Block a user