Repository navigation
fix: answer unaddressed review comments in recon, verification, experiments, viewer and docs - #242
Conversation
…s meter is each window's start A3 split error along and across each window's travel, but a wall plane removes error along the wall's normal, which is the across axis only while the walk runs straight along the wall. Windows whose reference path stays within 0.25 m or 0.5 m of its start-to-end line now get their own table. On MARViN at 20 ft along is 0.98 and 0.95 of the p90 there, so the conclusion holds on the windows that test it. Graded rows are unchanged. A4 already ranges from a fixed meter: each window is one session that starts at the meter, and the range runs from that start to the window's end. METHODS, README and the generated report now say so. #59 (comment) #59 (comment) #59 (comment) #59 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er changes The review page restored browser answers from a fixed localStorage key by photo id, so after a label correction or dataset update a stale Keep showed as done and was exported for a number nobody had checked. Each saved answer now records the number it was given for, and startingAnswers keeps it only while the page still shows that number; otherwise the ingested answer, if any, applies and the photo is open again. Answers saved before this change carry no number and are dropped the same way. #16 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ll gap rows_of_text joined every box sharing a row, so digits from an unrelated field further along the row could complete a labelled number and union its box with that field. Boxes now join only across a gap of at most three character widths (box width over its characters, in the image's own x units, so no aspect ratio is needed); a row splits into chains at wider gaps. Checked on the cached Vision reads of the labelled photos (clean.jsonl and scan.jsonl, every configuration, strict and lenient): limits from 2 to 6 widths change no number match and 1.5 loses three, so the committed results stand without a rerun. The sweep's degraded reads were not rescored. The limit does split unrelated fields on these photos, but no read depended on those joins. #16 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…past a marked end The unrun patch replays accepted cameras under the current marked ends, so sightings recorded before an end was marked are dropped and clearEnd has nothing to restore them from. The README now says so next to the patch's other known gaps. The patch bytes are unchanged, so patch-identities.json still holds. Alpha's in-app replay has the same shape; that is reported for the iOS lane, not changed here. #18 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Facing and overhead clearance used the fused volume's weight as "observed", and that weight only says some frame's ray reached a voxel. A capture with many frames could still report clearance that a single view vouched for, while wall and ground already need two positions 0.25 m apart. compute() now hands free_space a SeenFromTwo view of the volume. Its observed() also requires that two camera positions at least BASELINE_M apart each had a ray reach the sample, judged by that frame's own depth at the sample's pixel. free_space and _slab are unchanged, so this sits beside #240's change to the march rather than on it. On a synthetic 66-cell wall with 150 frames the free-space pass takes 8 s instead of 0.6 s. #20 (comment) #20 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…droom build_scene.py probed the overhead band at a hardcoded 6.5 ft. It now reads headroom.min_ft from server/rules.yaml at --rules-ref (default origin/t3/server, the e2e default) and records the ref, commit and value in build_report.json. case.json pins headroom 6.5 in rules_assumed. A server whose headroom check reports another threshold, from changed rules or a private override that git cannot show, is then marked "assumption mismatch" by the existing e2e check instead of being judged against a scene probed at the old height. Review thread: #13 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rebuild and unseen illustrations were animated WebPs in both colour schemes, so they kept moving under prefers-reduced-motion. Each <picture> now lists a still light and dark source first, gated on (prefers-reduced-motion: reduce). The stills are the last frame of each animation, the frame it holds longest, encoded as WebP at quality 85 (29 to 37 KB each). Review thread: #134 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…arks land When an older batch's count timer was pending and a later batch could not animate (motion paused, animation clock stopped, mark cap reached), the later batch skipped its immediate count update and the older timer wrote only its own snapshot, so the newest files stayed off the counters until some unrelated render. The last pending timer now writes the current totals; earlier timers still write their own snapshot, so a counter never runs ahead of marks still travelling. The timer bookkeeping moves out of app.js into count-timers.js so a test can drive it with fake timers. Two of its four tests fail when the timer writes only its snapshot, as on alpha. Review thread: #124 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…file Conduit.send built an array entry for every acknowledged file before capping the animation at six marks, so a large batch allocated memory in proportion to its size just to draw a few marks. markGroups now walks the per-group totals and returns only the marks, with the same evenly spaced picks as before. send() returns before reading the batch when motion is off, the batch predates the connection, or the line is not laid out. The tests compare markGroups with the old expansion over small batches, and check that a 5e9-file batch sends six marks and that motion-off reads nothing. On alpha, the send() tests fail (RangeError and a read with motion off). Review thread: #124 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Proposal 2 put the ground at a raw world groundY. ARKit corrects the meter anchor as tracking improves (proposal 10), so a world height recorded at one time and an anchor pose read at another give the server a wrong meter-to-ground offset, and with it wrong vertical placement and headroom. The proposal now carries groundOffset along the anchor's +y, which moves with the meter, as AGENTS.md asks of AR results. #22 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t mode Links used --phone (#2a78d6, 4.04:1 on --bg) and the blue and orange SVG labels used --phone and --server (#eb6834, 3.20:1 on --card), under the 4.5:1 WCAG AA minimum for normal text. New --phone-ink (#1e6ecb) and --server-ink (#c44400) carry text: same hue, OKLCH lightness lowered until they clear 4.5:1 on both backgrounds (4.63/5.06 and 4.61/5.03). Diagram fills, strokes and the focus ring keep the original tokens, which only need 3:1. In dark mode the ink tokens equal the fills, which already pass (4.69:1 and 5.26:1 on --card). Review thread: #14 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
post() read success and HTTPError bodies with an unbounded read(), and urllib's timeout applies per socket operation, so a server that trickled headers or body could hold a run past its budget or fill the harness's memory. post() now speaks http.client directly. A timer shuts the socket down at timeout_s, which ends any read in progress, and the body is read in 64 KB chunks up to MAX_RESPONSE_BYTES (4 MB) for every status. Past either limit the answer is status None with the reason as payload, and the callers report that reason. Tests use a local server that floods or trickles, for both 200 and 500, with a 16 KB cap and a 0.5 s deadline. One behaviour change: http.client does not read http_proxy/https_proxy as urllib did. Review thread: #13 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…quest M3 pairs each point's reference photo with the narrowest ray angle at or above 5 degrees, which keeps the patches alike for matching but triangulates worst. `--pair=widest` picks the widest qualifying angle and writes results/edge_geometry_widest_pair.*, leaving the pre-registered tables alone, so the two policies can be compared before M3's error is treated as representative. #59 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fog's lagged reveal mask eased from the previous frame unless the frame was settled. A scrub during playback, a LiDAR mode switch or the fog coming back on therefore eased from another view's mask and briefly left unmeasured regions clear. The renderer now snaps the mask unless the frame continues the last fogged one (same mode, same or next keyframe). Review thread: #86 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Surface fusion skips depth pixels below medium confidence, but free-space carving read them anyway. A low-confidence zero or far reading could mark a wall voxel's neighbour as seen-empty, and since free space and edges are both sticky, that left a lasting false boundary edge. Carving now applies the same confidence gate. The new tests build one keyframe of a flat wall with a strip of bad depth and check that only a confident hole carves. Review thread: #86 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`--still 2 --at 0.3` rendered keyframe 3 while the log named keyframe 2 and printed its stats. Stills are named and compared by keyframe, so the export now fails with the keyframe's on-screen time instead of writing a mislabelled image. The last keyframe takes any offset, since it stays on screen. Review thread: #86 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Constellation delays a dot's birth to when it became an edge. Feature points never do, so their edge time is the clamped 1e6 s and every simulated no-LiDAR point stayed hidden. The delay now applies only to voxel dots. Review thread: #86 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
make sim-app passed any run that reached STATE=result and logged a bundle, so an app that showed a cached or prebuilt scan straight away passed too. simrun gains --require-order (states that must appear in that order, others allowed between) and --require-then FIRST:THEN (every FIRST must be followed later by a THEN). sim-app now requires findMeter > meterCloseUp > wallWalk > markFeatures > uploading > result, and gapRequest:uploading, so a recapture round the app opens has to end in another upload. The names are ScanPhase on t3/ios-mvf. A round the app never opens leaves no STATE behind, and these checks cannot see it. The tests read the flags from the Makefile recipe. They accept the state sequences of recorded runs at a39d0a5, f14947e and c820cf1 and reject a jump to the result, a result without an upload, an upload before the walk, and a gap request that never led to an upload. Review thread: #13 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bours The less-coverage check skipped any start that the original sweep did not contain, so a changed scene could add a passing start in a gap or on a wall the original never swept. If the original already passed somewhere, the decision guard missed it too. Failing every None-to-pass would be wrong: coverage edges are evaluated starts, so moving them adds starts inside the original's gaps between runs. outcomes_near() reads such a start from the original's neighbouring runs on that wall. The server evaluates every start where a check can change outcome, plus the midpoints between them (solver.py docstring, t3/server 1d1e7e1), so between two evaluated starts the outcome is one of theirs. A new pass is then a violation only when neither neighbour passed, or when the original had no run on that wall. The more-error check had the same skip and now reads gaps the same way. Regressions: a pass inside a fail/unsure gap, a pass on an unswept wall while the original decision was already pass, and a pass past the last run all fail. A boundary that moved into a fail/pass gap still passes. Review thread: #13 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y tree The harness keyed screens on static-text and button labels only. A later screen with the same labels plus a text field, toggle, image or link was treated as already audited, so performAccessibilityAudit never ran on it. The key now lists every element in tree order by type, identifier and label. Unlabelled grouping containers are left out so view nesting does not decide the key. Values (typed text, toggle state, slider position) and frames are left out too, because they change while the screen stays the same and each change would start another audit and reset the idle timer. The A11Y_SCREEN labels the report shows are unchanged. Checked with swiftc -typecheck against the iOS 27 simulator SDK and XCTest. The UI-test fixture was not built or run. Review threads: #13 (comment) #13 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous two commits added the count-timer and mark tests to the "The tests cover" line, which open PR #238 also rewrites. Restore alpha's wording so the two branches merge without a conflict; the file table row still names count-timers.js, and each test file describes its own cases. Review threads: #124 (comment) #124 (comment) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 30489f8a6c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if configured.get(key) is not None | ||
| and not reported_assumption_values(key, result) | ||
| and abs(configured[key] - value) > EPS |
There was a problem hiding this comment.
Mark unreported private overrides as unverified
When a case assumes the public value and a server uses a private override but reports no corresponding value—for example, a wider private battery leaves no spot, nearest_considered, or width check—this condition suppresses the warning because configured[key] == value. judge() then runs expectations and geometry using the public rule and may claim contract_ok even though the response's policy.sources or rules_sha256 identifies different rules. Treat an unreported assumption as unverified whenever the response used non-public rules rather than using equality with the public default as evidence.
AGENTS.md reference: AGENTS.md:L33-L33
Useful? React with 👍 / 👎.
|
@codex review |
|
Codex Review: Didn't find any major issues. Nice work! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Keep loaded dimensions when the response claims the tested public fingerprint, including transformed responses. Reject malformed local case fields without losing the report. Reviews: #240 (comment) #240 (comment)
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c557e3af38
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| def run_starts(span: list[float], step_ft: float | None) -> Iterator[float]: | ||
| count = run_start_count(span, step_ft) | ||
| a, b = span | ||
| return itertools.chain((a + k * step_ft for k in range(count - 1)), (b,)) |
There was a problem hiding this comment.
Sample every pre-end start in each sweep run
For any nonzero run, run_start_count already counts the sampled starts before the final endpoint, but run_starts iterates range(count - 1), dropping the last step (and for a run shorter than one step, dropping the first endpoint entirely). Coverage, footprint, and declared-height checks therefore skip valid battery positions and can accept a passing result whose omitted start would fail. Iterate all counted pre-end samples before appending b.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
run_start_count returns count + 1, including the final endpoint. run_starts therefore emits count - 1 pre-end samples and b. At c557e3a, [0, 0.1] with step 1 emits [0, 0.1], and [0, 2] with step 1 emits [0, 1, 2]; changing the range would duplicate or overshoot the endpoint.
| def run_starts(span: list[float], step_ft: float | None) -> Iterator[float]: | ||
| count = run_start_count(span, step_ft) | ||
| a, b = span | ||
| return itertools.chain((a + k * step_ft for k in range(count - 1)), (b,)) |
There was a problem hiding this comment.
Sample the first start before stepping through sweep runs
For any nonzero run, run_start_count already counts the sampled starts before the final endpoint, but run_starts iterates range(count - 1), dropping the last step (and for a run shorter than one step, dropping the first endpoint entirely). Coverage, footprint, and declared-height checks therefore skip valid battery positions and can accept a passing result whose omitted start would fail. Iterate all counted pre-end samples before appending b.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
run_start_count returns count + 1, including the final endpoint. run_starts therefore emits count - 1 pre-end samples and b. At c557e3a, [0, 0.1] with step 1 emits [0, 0.1], and [0, 2] with step 1 emits [0, 1, 2]; changing the range would duplicate or overshoot the endpoint.
| n_i = np.flatnonzero(ok) | ||
| dh, dw = depth_map.shape | ||
| scale = dw / w | ||
| du = np.clip((u[n_i] * scale).astype(np.int64), 0, dw - 1) | ||
| dv = np.clip((v[n_i] * scale).astype(np.int64), 0, dh - 1) | ||
| measured = depth_map[dv, du] | ||
| reached = np.isfinite(measured) & (measured >= z[n_i] - tolerance(dist[n_i])) | ||
| out[n_i[reached], j] = True |
There was a problem hiding this comment.
Reject free-space rays blocked by fused occupied voxels
seen_through accepts a sample whenever the camera depth is at or behind the sample, but unlike seen_by it never calls vol.blocked (or otherwise tests occupied voxels between the camera and the sample). If the depth map sees through a thin or missed obstacle that the fused volume contains, two separated cameras can therefore mark the slab as observed and free_space can report clearance past the obstacle. Apply the same occupied-ray blocking test used by the regular visibility path before setting out.
Useful? React with 👍 / 👎.
|
@coderabbitai review |
|
Aggregate expectation failures with bounded examples and cap serialized diagnostic text across the report. Use exact string keys instead of adversarial numeric hashes. Make the pre-end sampling count explicit while preserving sampled starts. Reviews: Astra resource addendum; #242 (comment) #242 (comment)
Use the regular visibility path stop-short tolerance before crediting a camera ray. Preserve support for the target surface itself and require two unobstructed views. Review: #242 (comment)
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Prioritize the Markdown-visible problems array before duplicate JSON classifications. Regressions retain the first explanation for 1,000 contract or expectation failures without exceeding the shared diagnostic budget. Review: #240 (comment)
|
@codex review |
|
Codex Review: Didn't find any major issues. 🎉 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
This PR fixes review comments on ten already-merged PRs that nobody addressed before merging. It covers everything outside the iPhone app: the reconstruction worker, the verification harness, the packet proposals, four experiments, the integration viewer and the docs. Each original PR has its own section below, linked to its threads. The remaining items include contract decisions, an unsafe photos-only bound needing a product tradeoff, and a fixable replay defect reassigned to the iOS caretaker. They are listed at the end.
#20: recon: handoff to the server team
compute()now handsfree_spaceaSeenFromTwoview of the volume. Itsobserved()also requires two such positions, each with a ray that reaches the sample according to that frame's own depth. The clearance march batches 16 slabs at a time; wall-front geometry receives the raw volume while clearance samples retain the two-view check. Visibility projections are bounded and use cached packed partner masks instead of repeated dense camera-pair multiplication.#240's ZIP admission follow-up is included: footer selection agrees with Python's reader, and malformed comment footers or ZIP64 locator overrides are refused before metadata allocation. Tiny archive regressions preserve the cap and normal-comment extraction.
The handoff now lists two-view free-space coverage among the fixed behaviors. All 11 visibility tests pass; the overhead footprint and photos-only uncertainty decisions remain open. Handoff review.
Vet follow-ups protect the effective ZIP extraction directory and its ancestors/descendants before startup cleanup. Cached members are verified by name, size and streamed CRC and damaged caches are re-extracted under a lock. Overhead samples include both edges of the existing 0.56 m footprint, catching the missed 1.90 m eave; support for other battery depths still needs the server footprint contract. At df7b75d, twelve new recon cases failed before these fixes; the guarded recon suite passes 125 tests on #240 and 149 on #242.
The Sol breadth follow-up closes the occupied-slab bypass: obstructions always stop clearance marches, but a measured gap and observed band require two-view support at the hit. One camera and two nearby cameras now export no unsupported measurement; two separated cameras retain supported measurements. Both edges of the existing 0.56 m footprint remain covered. Four controls fail on aaacc0f before this repair. Reported corner allowances must also be finite and nonnegative before rule adoption, with zero allowed; seven new controls fail on aaacc0f. Guarded suites on 6c0639e pass 474 verification, 158 recon, 99 meter-closeup and 20 drift tests.
Facing, overhead and wall-band samples now measure heights from
ground.height_at(x,z)at each point, including slopes away from the wall. An uphill eave reported as 2.50 m before the fix is conservatively reported at 1.40 m above its cell ground. Observation at every slab still requires two separated camera positions. Local ground review.#13: verification: independent end-to-end checks (S4)
headroom.min_ftfromserver/rules.yamlat--rules-ref(defaultorigin/t3/server, as the e2e harness uses) and records the ref and value inbuild_report.json.case.json'srules_assumednow lists headroom, so the existing mismatch check catches a private override through the threshold the server reports.BATTERY_HEIGHT_FTis still a constant. No thread raised it, but it is the same kind of problem.post()now useshttp.client. One deadline covers DNS, TCP connect, TLS handshake, headers and body, and every status is capped at 4 MB. A bounded worker wait returns on deadline and closes sockets registered before TCP/TLS. OS DNS cannot be cancelled; a late result is checked before it can allocate or send. The cap's only evidence is that the largest result seen so far was 16 KB.http.clientignoreshttp_proxy. Tests cover reduced remaining TCP/TLS budgets, blocked DNS/TCP/TLS cleanup and a localhost TLS peer that never completes its handshake.make sim-apppassed on a shortcut (r4114865922).findMeter,meterCloseUp,wallWalk,markFeatures,uploadingandresultin that order. EachgapRequestmust be followed later by anuploading. The names areScanPhase's.server/solver.py:9-10).python -m pytest -qinverification/: 554 passed on the combined branch. Ruff lint and formatting pass for verification and recon. Facade regressions retain clipped tail probes and the active headroom in the same observed entry.This branch also contains #240's shared root Makefile dispatcher repair: verification is included, with standalone, missing-folder and failure-propagation cases in
tests/makefile.sh. That helper is the cross-folder change required to make the verification suite run from the root.The merged #240 deep-review repairs also require actual execution of all five hostile probes for full S2-8 credit. Generated and committed geometric cases bind their expectations to battery width and the applicable corner allowance; altered rules skip those expectations and do not establish acceptance. The shared root verifier target now runs locked dependency sync before child tests.
Codex found that a server-reported sweep such as
[0, 1e9]could allocate billions of starts. Sweep admission now rejects spans outside the scanned chain before sampling, and the sampler validates eagerly and yields lazily with a 10,000-sample cap including the endpoint. Oversized runs fail with a specific message rather than get truncated. Regressions cover both outcomes, both scan ends, a distant singleton, tiny rule steps and the exact cap boundary. Sweep sampling review.The rule-assumption follow-up compares case assumptions with reported spot width and rule-keyed thresholds. Geometry adopts a validated reported width only for a different policy fingerprint; a matching public fingerprint retains the loaded rules and checks reported dimensions against them. When the result omits a value that differs from the public rule, the report says "assumed public rules; server may override" and marks the record
assumptions unverified. Rule-dependent checks are withheld, rule-independent failures remain failures, and JSON, Markdown and the CLI expose the gap without granting acceptance. An otherwise clean inconclusive run exits 2. All 392 verification tests pass, covering matching overrides, real reported mismatches, absent values, report/scoreboard gates and the existing hostile-span bound. No private backend files were read. Rule assumption review.One runtime meter counts the geometry and comparison work that actually runs, including unsure checks, footprint lookups, ground grids, coverage and corner checks. Identical sweep records are deduplicated, and identical geometry checks are memoized. Structural admission rejects nonfinite numbers, overflowing span lengths, invalid dimensions and unknown wall references before geometry. The ground sampler is lazy; ordering comparisons use an interval index. A failed admission or invariant stops property comparisons, and any check exception becomes a named report problem. Exceeding the runtime limit produces
verification work limit exceeded (N samples). Verification ZIP admission still counts directories before metadata allocation, responses remain bounded at 4 MiB, and required simulator states must occur in order.The runtime limit is now 7,834,000 units, twenty times the remeasured valid peak of 391,700 on a saved ETH3D facade response. After caching, 35 valid public-fixture judgments including property variants peak at 31,649 units. Twenty additional measurements cover an 80-foot surveyed wall written as twenty walls, each subdivided 1, 4, 12, 13 or 20 times, original and mirrored, with full-judge resends. Those peak at 88,999 units. Another 468 distinct saved responses are included in the measurement corpus. These are operational work counts, not physical clearance accuracy.
The recorded public-solver response for an 80-foot wall has 683 candidates and passes with 29,760 actual visits and no ground-grid calls. Both missing-evidence branches use 130 visits for one unsure check or 10,000 duplicates. The old
2d959c7prediction rejects the valid response and invokes geometry 10,000 times in either branch. The remeasured valid peak is 391,700 units.Reported dimensions must be finite, positive and consistent with reported spans and footprint edges before rule adoption. A large reported width with no geometry to sample incurs only the work actually performed. Adopted dimensions and property variants charge the same judge meter. More error may add a failing run on a wall the original response never evaluated; a newly passing run remains a violation. Regressions cover invalid dimensions, span and footprint agreement, newly evaluated walls and bounded remaining response reads.
Current guarded suites pass: 594 verification, 168 recon, 99 meter-closeup and 20 drift-anatomy tests. All ran through
run-guarded.py --min-free-gib 8after disk met the 10 GiB startup threshold. Six sloped-ground controls and both reported-rule controls fail on 6c0639e before this repair. Ruff format checks pass in verification, recon and all touched experiment directories. The nine held formatting files preserve their Python syntax trees.Unknown public-rule assumptions still withhold rule-dependent checks and case expectations, but identical-input, mirror and coverage comparisons continue. A nondeterministic response therefore fails verification even when the result omits its width. Rule-independent checks review.
#22: packet: point to the server's capture packet 0.4 and propose 0.5 additions
meterAnchor.groundOffsetalong the anchor's +y, so the ground moves with the meter when ARKit corrects the anchor. The app's local packet already records it this way (ground_y_m,PacketWriter.swift:412).#59: experiments: signals lab round 1, which extra phone signals sharpen clearances
tests/test_metrics.py.run.py --pair=widestreruns M3 with the widest qualifying pair and writes separate results.modern_assumedposes, the 3-D p90 is 158.7 in for the widest pair against 154.6 for the narrowest, and 41% of points match either way. With exact poses the wide pair is worse, 156.4 in against 112.5, because fewer of its matches land within 2 px. P4 fails under both, so the narrow pairing isn't what makes M3 look bad.cv2.remap's row limit, so the epipolar patches are now sampled in chunks. A segment that fit before is still one chunk. The test for this fails on alpha.A3's failed 60% numeric criterion is now labeled a travel-axis proxy in README and METHODS. Wall-plane benefit is untested without wall annotations; all numerical tables remain unchanged.
#86: experiments: live dots, a macOS prototype of the holographic capture view
Tuning.minimumConfidence, as fusion already did. The new test fails with alpha'sDotField.swift.--still 2 --at 0.3rendered keyframe 3 under keyframe 2's name (r4115037787). An offset past the keyframe's time on screen is now an error that suggests--still 3, because stills are named and compared by keyframe.On b6bc4ad,
swift build --jobs 2succeeds andswift test --jobs 2passes all 45 tests in seven suites. Both commands ran throughrun-guarded.py --min-free-gib 8. The first test build exposed direct mutating calls inside#expect; the tests now evaluate those calls before asserting their results. Production playback and reset decisions are covered, including same-keyframe seek, settled scrub resume under both motion settings and ordinary pause/resume continuity. Metal pixels and native interaction were not inspected.#16: experiments: meter close-up reading, tap-to-confirm and two retake checks
PYTHONPATH=src python -m pytest -qinexperiments/meter-closeup/: 99 passed on the combined branch.The deep-review follow-up found that CSV import discarded which reader label a Keep confirmed. Downloads and ingest now preserve
shownplus whether it was recorded, including a reviewed empty label. Both the page and manifest reject unbound or mismatched imported Keeps. A legacy Keep cannot upgrade an earlier correction's verdict. Tests download, ingest, change the reader label and reload in fresh/stale browsers; numeric, empty and NONE labels, repeated ingest and prior corrections are covered. The original import fallback fails the new legacy-empty regression. Deep-review finding.#124: tools: viewer that films a capture reaching the server, as a labeled replay or read-only live view
count-timers.js. Each render queues what it drew and when its marks land. Its totals reach the counters once its own marks and every earlier render's marks have landed. A batch with no marks still shows, and counters never run ahead of marks in flight. Tests on a virtual clock fail with alpha's rule.markGroupschooses the at most six marks from per-group totals, making the same picks as before.send()reads nothing when motion is off.live.jsread status at once (model.js:197,live.js:79, test atmodel.test.js:311).node --test "test/*.test.js"intools/integration-viewer/: 104 passed, including the headless browser test.#134: docs: rebuild the README around the demo, with quick start, data and limits
prefers-reduced-motion: reduce. Each still is its animation's last frame, 29–37 KB. I checked the selection in headless Chrome against the live GitHub page and the new markup, under all four scheme and motion combinations.#14: docs: keep only the current plan and the facts that still hold
docs/how-it-works.htmlgains text-only colours--phone-inkand--server-ink, while diagram fills keep the originals. In light mode, links go from 4.04:1 to 4.63:1, blue labels from 4.42 to 5.06, and orange labels from 3.20 to 5.03. Dark mode is unchanged and already at least 4.69:1.Light theme at 900 px wide, from the page served locally. Dark-theme and 390 px captures were checked but aren't attached.
#18: Research handoff: live survey findings, options and tested prototypes
native-proposals/README.mdnow records it next to the patch's other known gaps, and the patch bytes are unchanged. Alpha's replay also drops regular sightings past current ends, but clearing a limit end callsreplayPastLimits()for past-limit ground. It does not rebuild those regular wall/ground sightings. The README distinguishes these behaviors. The remaining replay loss is a fixable defect reassigned to the iOS caretaker, not a policy decision.Verification accepts root
scene.jsonor a scene under one shared top-level capture folder, including the public API Finder fixture. Unlike the public API's root precedence, it refuses both forms together so the verifier has one unambiguous input. Every non-metadata entry must lie beneath the shared folder for the wrapped form. All entries still count toward archive limits. Duplicate and ambiguous layouts remain rejected. Wrapped bundle review.Merge order
Merge #240 first, then #242. #242 contains #240 at
a7b3169through merge commitdaa36a2. Both include alpha3c33ad7, retain the same runtime work meter and ingestion bounds, and preserve the shared Makefile dispatch repairs. Neither branch was rebased or force-pushed.Still open
The ground-reach, variable-footprint and yaw contracts remain open. Photos-only uncertainty is an existing unsafe bound needing a product tradeoff; the iOS replay defect has been reassigned.
clearEnd, reassigned to the iOS caretaker (#18 r4111600380).Checklist
Current validation limits
Scene/rule derivatives and wall lookups are cached per judgment. Direct coverage builds no ground fallback strips, and redundant collinear vertices no longer multiply work. Full judgments at 13 and 20 subdivisions fail at the old limit and pass now within 20% of the one-segment representation. Distinct evidence IDs and duplicate diagnostics use hash lookups.
Metadata admission precedes schema validation, copies and resend comparison. It bounds walls to 50, vertices per wall to 500, runs to 30,000, checks and requests to 16,000 each, numeric leaves to 1,000,000, JSON nodes to 2,000,000, nesting to 32 and string/key characters to 4 MiB per document. Local case rules have 64 queries. Boundary controls verify clean admission and specific over-limit diagnostics.
Reported widths and corner allowances now share the same handling in both PRs. A case mismatch uses the response's reported value. Geometry adopts a validated reported override only for a different policy fingerprint. Matching public fingerprints retain the loaded rules and contract-check all reported battery dimensions, route height and corner allowance, including transformed responses. An unreported value is unverified when policy sources include private rules or the normalized rule fingerprint differs from the tested public rules, even if the assumed numeric value equals the public default. Four private-source/fingerprint controls fail on
30489f8before this repair. Encrypted NPZ flags now trigger locked cache repair; the damaged-file control fails before the repair with a password-required RuntimeError.Research-handoff has ten pre-existing Ruff lint diagnostics, confirmed against 6c0639e. Its formatting checks pass, and the formatting changes preserve Python syntax trees.
Python checks use the existing Python 3.12 environment at
/Users/samgu/Programming Projects/house-scanning-real-intake-20261004/.venv/bin/python. Recon has 165 passing tests; its OpenCV 5.0 install is outside the declared<5range. No dependencies were installed. Root Makefile dispatch cases pass. No model inference, dataset regeneration, private backend, simulator or phone checks ran in this caretaker round. Earlier experiment/viewer/media evidence above belongs to the original Opus run.Summary by CodeRabbit
Null
rules_assumedand null expectation query arrays now producebad inputrecords before counting. A regression saves both failed cases and a subsequent valid case in one report. The shared repair is merged from #240, which lands first. The matching-public wrong-width and malformed-case controls fail ona7b3169. Public-policy review. Case metadata review.Repeated sweep and check expectation failures now produce one message per expectation, with a failure count, the reason once and at most three examples. A shared report budget retains at most 1,000 diagnostic entries and 262,144 serialized diagnostic characters, including duplicate JSON fields, and emits one omitted-count summary. Contract counts and acceptance are computed before display truncation; raw response payloads remain separate. Markdown-visible explanations receive budget priority over their duplicate JSON classifications. Both 1,000-error regressions retain the first explanation in the Markdown row and stay within the shared limits; both fail on
c32ee97. Numeric cache and interval-map keys use exact rational strings, preserving equal integer/float values while preventing cheap modulus collisions. Regressions cover 1,000 runs with a 4,096-character reason, oversized reasons, JSON escaping and 2,000 colliding integers across four key paths.The sampler count API now explicitly counts starts before the final endpoint;
run_startsyields those starts and then the endpoint. Pinneddb1e4c2controls confirm that the old implementation already checked the last pre-end start, checked a sub-step run's first start and charged each yielded sample. The new count-API assertions fail there; the functional sampling controls already pass. Sampler review 1. Sampler review 2.Free-space visibility now rejects camera rays blocked by fused occupied voxels, using the same stop-short tolerance as regular visibility. A nearer thin fused wall defeats both depth-backed rays, while clear rays and the target surface itself remain supported. The blocked-ray control fails on
c557e3a. Fused-ray review.