Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
231d835
fix(packet): qualify study evidence and proposed validation
SamGu-NRX Oct 13, 2026
ec357bb
fix(check): include independent verification in root dispatch
SamGu-NRX Oct 13, 2026
a5e976d
fix(verification): keep simulator evidence tied to its own run
SamGu-NRX Oct 13, 2026
c644217
fix(verification): validate interior footprints and replay failures
SamGu-NRX Oct 13, 2026
853c2df
fix(verification): reject incomplete evidence and stale input hashes
SamGu-NRX Oct 13, 2026
b5da197
fix(recon): preserve evidence and refuse incomplete cached outputs
SamGu-NRX Oct 13, 2026
1194523
fix(recon): rebuild caches with unsupported ZIP compression
SamGu-NRX Oct 13, 2026
aec1d01
experiments(drift-anatomy): test A3 on wall-parallel windows; say A4'…
SamGu-NRX Oct 13, 2026
bfb6c19
experiments(meter-closeup): drop a saved review verdict once its numb…
SamGu-NRX Oct 13, 2026
5595a06
experiments(meter-closeup): join OCR boxes in a row only across a sma…
SamGu-NRX Oct 13, 2026
0cf5f48
research-handoff: record that the ground-replay patch loses evidence …
SamGu-NRX Oct 13, 2026
2a337e3
recon: free space needs two camera positions before it counts as seen
SamGu-NRX Oct 13, 2026
706c17a
verification(eth3d-facade): probe overhead coverage at the rules' hea…
SamGu-NRX Oct 13, 2026
8ed76ab
docs(readme): show still frames to readers who ask for reduced motion
SamGu-NRX Oct 13, 2026
a4d1008
fix(integration-viewer): show batches that drew no marks once older m…
SamGu-NRX Oct 13, 2026
50c9ec4
perf(integration-viewer): pick a batch's marks without listing every …
SamGu-NRX Oct 13, 2026
a92333e
packet: propose the ground height in the meter anchor's frame
SamGu-NRX Oct 13, 2026
1f418a2
docs(how-it-works): give phone and server text 4.5:1 contrast in ligh…
SamGu-NRX Oct 13, 2026
9c95004
verification(e2e): bound every answer by bytes and an overall deadline
SamGu-NRX Oct 13, 2026
6ddd229
experiments(edge-geometry): rerun M3 with the widest photo pair on re…
SamGu-NRX Oct 13, 2026
be450fd
live-dots: reset the fog mask when the view jumps
SamGu-NRX Oct 13, 2026
dd7691e
live-dots: carve free space only from confident depth
SamGu-NRX Oct 13, 2026
bccb4d6
live-dots: reject a --still offset that plays into the next keyframe
SamGu-NRX Oct 13, 2026
6284b51
live-dots: show feature points in the constellation scheme
SamGu-NRX Oct 13, 2026
d2085b0
verification(sim-app): require the ordered capture and upload flow
SamGu-NRX Oct 13, 2026
159a156
Merge live-dots review fixes (#86)
SamGu-NRX Oct 13, 2026
772defc
verification(resultcheck): compare a newly swept start with its neigh…
SamGu-NRX Oct 13, 2026
61ab937
verification(a11y-audit): identify a screen by its whole accessibilit…
SamGu-NRX Oct 13, 2026
e5f30f5
Merge verification harness review fixes (#13)
SamGu-NRX Oct 13, 2026
d75e7a9
docs(integration-viewer): leave the tests sentence for PR #238 to change
SamGu-NRX Oct 13, 2026
37218bf
docs(how-it-works): draw the coverage zone as every check's reach, no…
SamGu-NRX Oct 13, 2026
44f81f8
experiments(edge-geometry): match along epipolar segments longer than…
SamGu-NRX Oct 14, 2026
e020a15
fix(integration-viewer): keep counters behind every mark still travel…
SamGu-NRX Oct 14, 2026
e3165da
docs(how-it-works): call the pool and driveway reaches placeholders
SamGu-NRX Oct 14, 2026
fbe3e85
Merge viewer and docs review fixes (#124, #134, #14)
SamGu-NRX Oct 14, 2026
188c126
experiments(edge-geometry): M3 with the widest photo pair is no better
SamGu-NRX Oct 14, 2026
1b89e29
verification: treat an answer cut short of its Content-Length as no a…
SamGu-NRX Oct 14, 2026
cac5fa0
experiments(meter-closeup): keep a browser correction when its number…
SamGu-NRX Oct 14, 2026
e4cc551
verification: a new pass past the original sweep's ends is unsupported
SamGu-NRX Oct 14, 2026
d51c645
verification: each gap request needs its own upload before the result
SamGu-NRX Oct 14, 2026
a0554c8
recon: build the camera-pair matrix once for free-space queries
SamGu-NRX Oct 14, 2026
d0dbed8
live-dots: bound a --still offset into the last keyframe by playback'…
SamGu-NRX Oct 14, 2026
856ffb0
verification: refuse a rules headroom at or above the scanned overhea…
SamGu-NRX Oct 14, 2026
739c262
experiments(meter-closeup): keep a confirmed correction when its labe…
SamGu-NRX Oct 14, 2026
3659fb5
merge: combine pipeline evidence repairs with follow-up fixes
SamGu-NRX Oct 14, 2026
cfd357c
merge: retain facade tail regression from pipeline fix
SamGu-NRX Oct 14, 2026
7ae364d
test: keep facade tail probes inside wall extents
Oct 14, 2026
b646b9a
fix: close pipeline follow-up review gaps
SamGu-NRX Oct 14, 2026
aa44d1f
fix: retain reviewed meter labels across CSV ingest
SamGu-NRX Oct 14, 2026
10f0fb1
fix: reject ambiguous archives and incomplete acceptance evidence
SamGu-NRX Oct 14, 2026
109bdf4
merge: retain deep pipeline review fixes and deadline regressions
SamGu-NRX Oct 14, 2026
b6bc4ad
test(live-dots): evaluate fog mutations before assertions
SamGu-NRX Oct 14, 2026
df7b75d
fix(verification): bound sweep sampling before geometry checks
SamGu-NRX Oct 14, 2026
adf807a
Merge bounded sweep verification from #240
SamGu-NRX Oct 14, 2026
aaacc0f
fix(verification): distinguish reported rules from public assumptions
SamGu-NRX Oct 14, 2026
851814d
fix(pipeline): bound response geometry and preserve capture caches
SamGu-NRX Oct 14, 2026
17425e7
fix(verification): reject invalid reported dimensions and allow new f…
SamGu-NRX Oct 14, 2026
03b0f0e
docs(recon): distinguish repaired footprint edges from depth policy
SamGu-NRX Oct 14, 2026
2d959c7
docs(recon): describe the remaining battery depth assumption
SamGu-NRX Oct 14, 2026
2e17888
Merge shared geometry admission and pipeline vet fixes from #240
SamGu-NRX Oct 14, 2026
8a6d9ed
Merge the final #240 footprint handoff
SamGu-NRX Oct 14, 2026
6c0639e
fix(pipeline): require two views for occupied clearance measurements
SamGu-NRX Oct 14, 2026
68cb685
fix(verification): meter actual geometry and comparison work
SamGu-NRX Oct 14, 2026
ba158ea
fix(pipeline): merge runtime checks and sample above local ground
SamGu-NRX Oct 14, 2026
717e6da
fix(verification): accept wrapped captures and retain alpha checks
SamGu-NRX Oct 14, 2026
60f8e9c
fix(pipeline): carry capture compatibility and alpha checks
SamGu-NRX Oct 14, 2026
67b10e5
fix(verification): reject ambiguous capture scene paths
SamGu-NRX Oct 14, 2026
30489f8
fix(pipeline): share unambiguous capture selection
SamGu-NRX Oct 14, 2026
45645f0
fix(verification): cache scene geometry and bound metadata work
SamGu-NRX Oct 14, 2026
a7b3169
fix(pipeline): verify reported rules and repair encrypted caches
SamGu-NRX Oct 14, 2026
8c1978e
fix(pipeline): merge cached geometry and bounded metadata
SamGu-NRX Oct 14, 2026
daa36a2
fix(pipeline): carry reported-rule and encrypted-cache repairs
SamGu-NRX Oct 14, 2026
db1e4c2
fix(verification): enforce public policy and validate case metadata
SamGu-NRX Oct 14, 2026
055c2e8
Merge public-policy validation and safe case admission from #240
SamGu-NRX Oct 14, 2026
c557e3a
test(verification): identify private override fixtures explicitly
SamGu-NRX Oct 14, 2026
c32ee97
fix(verification): bound diagnostics and harden numeric cache keys
SamGu-NRX Oct 14, 2026
8f51757
Merge bounded diagnostics and numeric cache keys from #240
SamGu-NRX Oct 14, 2026
1ed45b6
fix(recon): reject free-space rays blocked by fused geometry
SamGu-NRX Oct 14, 2026
1428d04
fix(verification): preserve Markdown explanations within output budget
SamGu-NRX Oct 14, 2026
c4461b2
Merge Markdown diagnostic priority fix from #240
SamGu-NRX Oct 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
# Suite targets follow their CI jobs where one exists. The viewer has no CI job yet.
# `make check` runs server, web and ios, then scoring, measure-lab, evals, recon
# meter-closeup and the integration viewer where the branch has them.
# meter-closeup, verification and the integration viewer where the branch has them.
# tests/makefile.sh checks this dispatch with stub suites.

XCODEGEN ?= xcodegen
# Must match XCODEGEN_VERSION in .github/workflows/ios.yml; other versions write a different project.
XCODEGEN_VERSION := 2.46.0

# The file each experiment suite's target needs. These suites arrive in separate pull requests, so
# The file each optional suite's target needs. These suites arrive in separate pull requests, so
# `check` includes one only when its file exists and the Makefile works before and after each
# merge. Once all five are on main, list them in `check` directly so a deleted folder fails.
# merge. Once all seven are on main, list them in `check` directly so a deleted folder fails.
SCORING := experiments/scoring/pyproject.toml
MEASURE_LAB := experiments/measure-lab/Makefile
EVALS := experiments/evals/Makefile
RECON := recon/Makefile
METER_CLOSEUP := experiments/meter-closeup/Makefile
VERIFICATION := verification/Makefile
INTEGRATION_VIEWER := tools/integration-viewer/package.json

# $(call present,FILE,TARGET) is TARGET when FILE exists, otherwise nothing.
present = $(if $(wildcard $(1)),$(2))
# $(call require,FILE,PR): stop before any command runs when the suite's file is missing.
require = @test -f $(1) || { echo "make $@: $(1) is missing; the suite arrives with pull request $(2)." >&2; exit 1; }

.PHONY: check server web ios ios-project smoke scoring measure-lab evals recon meter-closeup integration-viewer
.PHONY: check server web ios ios-project smoke scoring measure-lab evals recon meter-closeup verification integration-viewer

check: server web ios \
$(call present,$(SCORING),scoring) \
$(call present,$(MEASURE_LAB),measure-lab) \
$(call present,$(EVALS),evals) \
$(call present,$(RECON),recon) \
$(call present,$(METER_CLOSEUP),meter-closeup) \
$(call present,$(VERIFICATION),verification) \
$(call present,$(INTEGRATION_VIEWER),integration-viewer)

server:
Expand Down Expand Up @@ -94,6 +96,12 @@ meter-closeup:
cd experiments/meter-closeup && uv sync --locked
$(MAKE) -C experiments/meter-closeup check

# Match verification CI's locked sync so a stale lockfile cannot pass the local check.
verification:
$(call require,$(VERIFICATION),#13)
cd verification && uv sync --locked
$(MAKE) -C verification test

integration-viewer:
$(call require,$(INTEGRATION_VIEWER),#124)
cd tools/integration-viewer && node --test "test/*.test.js"
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ The criteria (e.g. the distance the battery must be from the gas meter) exist in
Below, one wall makes the whole trip, from photos to a checked spot. The models build the wall and name what's on it. The last step, the rule checks, is that deterministic evaluation.

<picture>
<source media="(prefers-color-scheme: dark) and (prefers-reduced-motion: reduce)" srcset="docs/readme/rebuild-dark-still.webp">
<source media="(prefers-color-scheme: light) and (prefers-reduced-motion: reduce)" srcset="docs/readme/rebuild-light-still.webp">
<source media="(prefers-color-scheme: dark)" srcset="docs/readme/rebuild-dark.webp">
<img alt="An animated drawing of one wall in six steps. Photos arrive, each with the phone's position. Points are matched between them. A ruler marks feet out from the meter. Dots fill in the wall and the ground, while the left side nobody filmed stays hatched and reads Not seen. The window, meter, AC unit and gravel get labels. Last, a battery appears 12 ft right of the meter with its cable, beside a card where wall behind it, ground under it, open space in front and a 13.6 ft cable run all pass." src="docs/readme/rebuild-light.webp" width="100%">
</picture>
Expand All @@ -75,6 +77,8 @@ Here's where each piece runs. The phone uploads the capture to Google Cloud Stor
## Unseen? Then Unsure

<picture>
<source media="(prefers-color-scheme: dark) and (prefers-reduced-motion: reduce)" srcset="docs/readme/unseen-dark-still.webp">
<source media="(prefers-color-scheme: light) and (prefers-reduced-motion: reduce)" srcset="docs/readme/unseen-light-still.webp">
<source media="(prefers-color-scheme: dark)" srcset="docs/readme/unseen-dark.webp">
<img alt="A wall with the left side hazed over. Three checks read Not seen. The haze sweeps away, the checks turn Unsure, then settle: wall and ground pass, clear space fails, and the spot reads Not here." src="docs/readme/unseen-light.webp" width="100%">
</picture>
Expand Down
69 changes: 40 additions & 29 deletions docs/how-it-works.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
--sky:#e2edf8; --wall:#e8dcc4; --eave:#6b5a4a; --ground:#c9dcb0; --bush:#6f9a52;
--tape:#f3cf4b; --tape-ink:#3d3106;
--phone:#2a78d6; --server:#eb6834; --fog:#8d8d86; --battery:#2f3e4e;
/* Text in the phone and server colours. The fills above are 4.0:1 and 2.9:1 on --bg, too
faint for small text; these keep the hue with OKLCH lightness lowered until text clears
4.5:1 on --bg (4.63 and 4.61) and on --card (5.06 and 5.03). */
--phone-ink:#1e6ecb; --server-ink:#c44400;
--meterbox:#6f7680; --meter:#a9d3f2; --gas:#b9b3a6; --glass:#bfe0f5;
--zone:rgba(208,59,59,.14); --zone-line:#d03b3b;
--pass:#107a2a; --fail:#b83232; --fail-ink:#a12b2b; --unsure:#fab219;
Expand All @@ -24,6 +28,8 @@
--sky:#1c2734; --wall:#4a4033; --eave:#8a7562; --ground:#2f4128; --bush:#5d8a45;
--tape:#7a6016; --tape-ink:#fff3c4;
--phone:#3987e5; --server:#e8683a; --fog:#6e6e68; --battery:#cfd8e3;
/* The dark fills already read as text: 4.69:1 and 5.26:1 on --card. */
--phone-ink:#3987e5; --server-ink:#e8683a;
--meterbox:#8f97a3; --meter:#5c8fb8; --gas:#7d786d; --glass:#6f9fbf;
--zone:rgba(230,103,103,.22); --zone-line:#e66767;
--pass:#107a2a; --fail:#b83232; --fail-ink:#f28b8b; --unsure:#fab219;
Expand All @@ -42,7 +48,7 @@
.prose{max-width:58ch}
.meta{font-family:var(--sans);color:var(--muted);font-size:15px}
.lede{font-size:20px;line-height:1.45;max-width:60ch}
a{color:var(--phone);text-underline-offset:3px}
a{color:var(--phone-ink);text-underline-offset:3px}
a:focus-visible,summary:focus-visible{outline:2px solid var(--phone);outline-offset:3px;border-radius:2px}
code{font-family:var(--mono);font-size:.86em;background:var(--code-bg);padding:1px 5px;border-radius:3px;overflow-wrap:anywhere}
ul,ol{padding-left:1.3em}
Expand Down Expand Up @@ -99,8 +105,8 @@
.lab.s{font-size:16px}
.lab.b{font-weight:600}
/* Colour utilities come after .lab and .t so they win at equal specificity. */
.lab.blue,.t.blue{fill:var(--phone)}
.lab.orange,.t.orange{fill:var(--server)}
.lab.blue,.t.blue{fill:var(--phone-ink)}
.lab.orange,.t.orange{fill:var(--server-ink)}
.lab.red,.t.red{fill:var(--fail-ink)}
.lab.mu,.t.mu{fill:var(--muted)}
.tp{font-family:var(--sans);font-size:15px;fill:var(--tape-ink);font-weight:600}
Expand Down Expand Up @@ -715,43 +721,48 @@ <h3>Unseen means unsure</h3>
</figure>

<h3>Coverage is a fixed zone</h3>
<p class="prose">Not the whole house, just a zone around the meter. The app always knows exactly what's left.</p>
<p class="prose">Not the whole house. The zone is every spot the cable can reach, plus everything the checks on those spots look at. The rules fix it before the scan starts, so the app always knows exactly what's left.</p>
<figure class="narrow">
<svg viewBox="0 0 480 300" role="img" aria-labelledby="cvt cvd">
<title id="cvt">The zone a scan must cover, seen from above</title>
<desc id="cvd">A plan view of the house with the electric meter on its front wall. A dashed blue rectangle marks the zone the checks need: the wall 20 feet either side of the meter and the ground in front of it out to 13 feet. Everything outside it is grey haze labelled not needed. Inside, a bush stands in front of the wall, and the strip of wall behind it is unseen, so checks there are UNSURE. A dotted path shows the phone walking along the zone.</desc>
<!-- 1 ft = 8 px, meter at x=240, wall face at y=110 -->
<desc id="cvd">A plan view of the house with the electric meter on its front wall. An orange band along the wall marks the candidate battery spots, 20 feet of cable either side of the meter. A dashed blue outline marks the zone the checks need: that band grown by how far each check reaches, so it runs past the cable's reach at both ends and out over the ground in front, with rounded front corners. A bracket under it reads needed: all of it, past the cable's reach too. Everything outside is washed out and labelled no check looks here. Inside the zone, a bush stands in front of the wall, and the strip of wall behind it is unseen, so checks there are UNSURE. A dotted path shows the phone walking through the zone.</desc>
<!-- 1 ft = 7 px, meter at x=240, wall face at y=110. Candidate footprints (22 in deep, 13 px)
fill a band within 20 ft of cable, x 100 to 380. The zone is that band grown by the
farthest check. Its front sits at the 13 ft of ground the pool and driveway checks need
(docs/00-overview.md), y=201, so it grows the band by about 11 ft (78 px): the same
reach puts its ends at x 22 and 458 and rounds its front corners. -->
<rect width="480" height="300" fill="var(--ground)"/>
<rect x="40" y="16" width="400" height="88" fill="var(--eave)"/>
<rect x="40" y="104" width="400" height="6" fill="var(--wall)"/>
<text class="lab b" x="240" y="48" text-anchor="middle">house, seen from above</text>
<!-- cable reach bracket -->
<rect x="0" y="16" width="480" height="88" fill="var(--eave)"/>
<rect x="0" y="104" width="480" height="6" fill="var(--wall)"/>
<text class="lab b" x="240" y="44" text-anchor="middle">house, seen from above</text>
<!-- candidate spots: cable reach bracket and the band of footprints -->
<g stroke="var(--server)" stroke-width="2.5">
<line x1="100" y1="88" x2="380" y2="88"/><line x1="100" y1="81" x2="100" y2="95"/><line x1="240" y1="81" x2="240" y2="95"/><line x1="380" y1="81" x2="380" y2="95"/>
</g>
<text class="lab s" x="240" y="74" text-anchor="middle">candidate spots: 20 ft of cable either side</text>
<rect x="100" y="110" width="280" height="13" fill="var(--server)" fill-opacity=".22" stroke="var(--server)" stroke-width="2"/>
<!-- outside the zone: washed out, not hazed, because haze means unseen and needed -->
<path d="M0 104 H480 V300 H0 Z M22 104 V123 A78 78 0 0 0 100 201 H380 A78 78 0 0 0 458 123 V104 Z" fill="var(--card)" fill-opacity=".6" fill-rule="evenodd"/>
<!-- the zone -->
<path d="M22 104 V123 A78 78 0 0 0 100 201 H380 A78 78 0 0 0 458 123 V104" fill="none" stroke="var(--phone)" stroke-width="2.5" stroke-dasharray="7 4"/>
<g stroke="var(--phone)" stroke-width="2.5">
<line x1="80" y1="88" x2="400" y2="88"/><line x1="80" y1="81" x2="80" y2="95"/><line x1="240" y1="81" x2="240" y2="95"/><line x1="400" y1="81" x2="400" y2="95"/>
<line x1="22" y1="214" x2="458" y2="214"/><line x1="22" y1="207" x2="22" y2="221"/><line x1="458" y1="207" x2="458" y2="221"/>
</g>
<text class="lab" x="240" y="76" text-anchor="middle">cable reach: 20 ft either side</text>
<!-- haze outside the needed zone -->
<rect x="0" y="102" width="80" height="198" fill="url(#fogpat)"/>
<rect x="400" y="102" width="80" height="198" fill="url(#fogpat)"/>
<rect x="80" y="214" width="320" height="86" fill="url(#fogpat)"/>
<text class="lab b" x="240" y="266" text-anchor="middle">not needed</text>
<!-- needed zone -->
<rect x="80" y="104" width="320" height="110" fill="none" stroke="var(--phone)" stroke-width="2.5" stroke-dasharray="7 4"/>
<text class="lab s b blue" x="240" y="238" text-anchor="middle">needed: all of it, past the cable's reach too</text>
<text class="lab mu" x="240" y="280" text-anchor="middle">no check looks here</text>
<!-- meter -->
<rect x="234" y="101" width="12" height="9" rx="1.5" fill="var(--meterbox)"/>
<text class="lab" x="252" y="130">meter</text>
<text class="lab" x="228" y="142" text-anchor="end">meter</text>
<!-- bush hiding a strip of wall -->
<rect x="318" y="101" width="24" height="9" fill="url(#fogpat)" stroke="var(--fail-ink)" stroke-width="1.5"/>
<circle cx="330" cy="124" r="12" fill="var(--bush)"/>
<text class="lab" x="320" y="158" text-anchor="middle">wall behind the bush:</text>
<text class="lab" x="320" y="178" text-anchor="middle">unseen, so UNSURE</text>
<rect x="333" y="101" width="24" height="9" fill="url(#fogpat)" stroke="var(--fail-ink)" stroke-width="1.5"/>
<circle cx="345" cy="124" r="11" fill="var(--bush)"/>
<text class="lab s" x="345" y="152" text-anchor="middle">wall behind the bush:</text>
<text class="lab s" x="345" y="170" text-anchor="middle">unseen, so UNSURE</text>
<!-- the phone's path -->
<line x1="96" y1="186" x2="384" y2="186" stroke="var(--phone)" stroke-width="3" stroke-dasharray="1 7" stroke-linecap="round"/>
<use href="#phone" x="140" y="173"/>
<text class="lab b blue" x="90" y="132">needed: all of it</text>
<text class="lab" x="392" y="208" text-anchor="end">ground out to 13 ft</text>
<line x1="70" y1="186" x2="410" y2="186" stroke="var(--phone)" stroke-width="3" stroke-dasharray="1 7" stroke-linecap="round"/>
<use href="#phone" x="150" y="173"/>
</svg>
<figcaption>The zone: wall within 20 ft of cable each side, ground out to 6 to 13 ft, and headroom above. It reaches a little past 20 ft for clearances at the edge.</figcaption>
<figcaption>Each check reaches out from the spot it tests: 3 ft along the wall for gas meters, AC units, doors and windows, 5 ft for a driveway and 10 ft for a pool (both placeholders, with no public value), and up for headroom and wall equipment. So the zone runs past the 20 ft of cable at both ends, and over the ground out to 13 ft. Any part of it nobody saw keeps its checks UNSURE.</figcaption>
</figure>

<h3>LiDAR helps but isn't required</h3>
Expand Down
Binary file added docs/readme/rebuild-dark-still.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/readme/rebuild-light-still.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/readme/unseen-dark-still.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/readme/unseen-light-still.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions experiments/drift-anatomy/METHODS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ The server allows 0.16 ft of error per foot along the wall. That allowance domin

- **A1, return to the meter.** When a walk comes back within 0.3 m of an earlier point more than 30 s later, ARKit's closure residual r is the error in the displacement between the two visits. Does r bound the largest error between the visits?
- **A2, scale.** Is ARKit's scale one number per walk? This measures the spread of scale over sliding 5 m windows within a walk.
- **A3, the wall plane.** What share of the error runs across the direction of travel, which a wall plane would remove, compared with along it?
- **A4, a range to the meter.** A second phone left at the meter ranges the walking phone by UWB (σ 10 cm, simulated) at every window end. What is the p90 left over?
- **A3, along and across travel.** What share of the error runs across the direction of travel, compared with along it? A wall plane removes the across component only when travel is parallel to that wall; these walks do not annotate that orientation.
- **A4, a range to the meter.** A second phone left at the meter ranges the walking phone by UWB (σ 10 cm, simulated) at every window end. What is the p90 left over? Each window is one session that starts at the meter: the walking phone leaves the meter at the window's start, the second phone stays there, and the range runs from that start to the window's end. Sliding the start along a walk samples many meter placements; the error depends on the path walked from the meter, not on where in the dataset the meter sits.

## Pass criteria, fixed before the run

Expand All @@ -20,13 +20,13 @@ The server allows 0.16 ft of error per foot along the wall. That allowance domin

## Result

All four fail. Tables: [results/drift_anatomy.md](results/drift_anatomy.md).
A1, A2 and A4 fail their numeric criteria. A3 fails the 60% criterion for a travel-axis proxy; this is not evidence that a wall-plane experiment failed. Wall-plane benefit remains untested without wall annotations. Tables: [results/drift_anatomy.md](results/drift_anatomy.md).

- **A1.** 30 of 56 MARViN loops (54%). ADVIO has no revisit under 0.3 m while ARKit tracks. Scale and heading error cancel on return, so r misses them.
- **A2.** 5.7% SD on MARViN, 19% on ADVIO: drop. A few outlier windows inflate MARViN's SD; its robust SD is 1.8%.
- **A3.** At 20 ft, along is 0.92 of the p90 on MARViN and 0.76 on ADVIO.
- **A3.** At 20 ft, along is 0.92 of the p90 on MARViN and 0.76 on ADVIO. The straight-path check selects windows by reference-path deviation from their start-to-end line: within 0.25 m, along is 0.98 of the p90 on MARViN and 0.75 on ADVIO; within 0.5 m, 0.95 and 0.75. These untuned, non-pre-registered filters select straightness only. With no wall annotations, they cannot identify wall-parallel travel or establish a wall-plane constraint's benefit.
- **A4.** MARViN goes from 10.4 and 13.6 in to 7.7 and 8.5 in. At σ 10 cm the range's own p90 is 6.5 in, so the bar was nearly out of reach. At 5 cm: 4.9 and 6.1 in.

**Run:** `uv run python run.py`. Needs the evals checkout at 190ed33 (`EVALS_HARNESS`) and MARViN and ADVIO in `~/house-scanning-data`.

**What it changes:** the error worth attacking runs along travel. A range to the meter reduces it, a wall plane wouldn't, and r can't bound a session.
**What it changes:** the error worth attacking runs along travel. A range to the meter reduces it, and r cannot bound a session. These unannotated walks do not establish whether a wall-plane constraint helps.
8 changes: 4 additions & 4 deletions experiments/drift-anatomy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Question

The server allows 0.16 ft of error per foot along the wall, which dominates a check's error bar beyond a few feet. Which part of ARKit's error is worth attacking? A1 asks whether returning to the meter bounds it, A2 whether scale is one number per walk, A3 how much runs across travel, where a wall plane would help, and A4 what a UWB range to the meter leaves. The data is MARViN (iPhone 14 Pro Max) and ADVIO (iPhone 6s); [METHODS.md](METHODS.md) has the details.
The server allows 0.16 ft of error per foot along the wall, which dominates a check's error bar beyond a few feet. Which part of ARKit's error is worth attacking? A1 asks whether returning to the meter bounds it, A2 whether scale is one number per walk, A3 how much runs across travel, and A4 what a UWB range to the meter leaves. Each window stands for a session that starts at the meter, so in A4 the second phone sits at the window's start. The data is MARViN (iPhone 14 Pro Max) and ADVIO (iPhone 6s); [METHODS.md](METHODS.md) has the details.

## Pass criteria, fixed before the run (397507f)

Expand All @@ -13,13 +13,13 @@ The server allows 0.16 ft of error per foot along the wall, which dominates a ch

## Result

All four fail ([tables](results/drift_anatomy.md)).
A1, A2 and A4 fail their numeric criteria. A3 fails the 60% criterion for a travel-axis proxy; the unannotated walks cannot test wall-plane benefit ([tables](results/drift_anatomy.md)).

- **A1.** The closure residual bounds the peak error in 30 of 56 loops. Scale and heading error cancel on return.
- **A2.** Scale spread within a walk is 1.8% robust SD (5.7% SD) on MARViN.
- **A3.** At 20 ft, the along-travel p90 is 9.6 of 10.4 in.
- **A3.** At 20 ft, the along-travel p90 is 9.6 of 10.4 in. In the straight-path check, along is 0.95 to 0.98 of the total on MARViN (added after review). The walks have no wall annotations, so this does not establish wall-parallel travel or the benefit of a wall-plane constraint.
- **A4.** UWB cuts 20 ft from 10.4 to 7.7 in at σ 10 cm, and to 4.9 in at σ 5 cm.

**Run:** `uv run python run.py`: 20 s. Needs the evals checkout at 190ed33 and MARViN and ADVIO in `~/house-scanning-data`.

**What it changes:** the error worth attacking runs along travel. Measuring a span inside one photo avoids it. A wall plane, a return to the meter or one ruler at the meter don't.
**What it changes:** the error worth attacking runs along travel. Measuring a span inside one photo avoids it. The return-to-meter and one-ruler criteria fail. These unannotated walks do not establish whether a wall-plane constraint helps.
Loading