Skip to content

Draw unclean AR spots as outlines and face the closest spot in the result model - #146

Merged
AidenJohnston merged 4 commits into
betafrom
t3/110-result-details-followups
Sep 27, 2026
Merged

AidenJohnston merged 4 commits into
betafrom
t3/110-result-details-followups

Conversation

@AidenJohnston

@AidenJohnston AidenJohnston commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

Part of #110.

The two original items on #110 (needsPerson checks under "Settles", rejected sweep extents) were fixed by #91 and are on beta. This PR takes the follow-ups from SamGu-NRX's three comments on #110. The fourth bot item in the second comment (capturable missing evidence without a linked check) stays open; see Known gaps.

What the old code did

  • Camera heading (bot 4114320391). ResultScene3D.orbitTarget already circled spot ?? nearestSpot, but orbitHeading still read result.spot only. A reject whose closest spot lay round a corner opened facing the meter's piece of wall, not the candidate's.
  • AR battery for an unclean spot (bot 4114320393). The result card's 3D model draws a spot that might stand in the meter's working space as a dashed footprint outline with no battery. "See it on your wall" drew a solid battery there, in both the RealityKit model (ResultARModel) and the Canvas fallback (BatteryOverlay). The AR title checked only decision == .pass && policyApproved, so a pass whose working-space check wasn't clean would have read "Your battery could go here".
  • Outline lift (bot 4114320399). The footprint outline sat at a fixed 2 cm while zones stacked at 6 mm + 3 mm each. The sixth zone (2.1 cm) came through the outline, and the fifth (1.8 cm) fought it for depth.
  • Show me after the camera failed (third comment). Once the camera failed after the scan was sent (spatialResultAvailable == false), the result screen hid the AR button but kept offering the card's filled "Show me" (action.showMe), the check lines' "Show me" and Details' "Capture it now". Each opened a capture with no frames coming. captureMissing didn't check the source either.

What changed

  • orbitHeading faces the same spot the camera circles: the spot, else the closest spot tried, else the meter.
  • The AR scene and the Canvas overlay draw an unclean spot as a dashed outline of its footprint, tinted by the working-space outcome as on the card, with no battery. The AR title needs spotIsClean as well before it says "Your battery could go here". Otherwise it keeps "The spot an installer will check". The VoiceOver label says it is an outline.
  • "See it on your wall" aims its checks at the mark it draws (review 4114877760). For an unclean spot, spotCenter(on:) now targets the outline's ground-level centre instead of half the battery height, via HouseScanKit ResultMarkLayout.focusHeight. Both the edge chevron (SpotDirection, over Canvas and RealityKit) and the AR scene's in-view check (ScanEngine.showResultInCamera focus for resultIsDrawn()) use it. A clean battery keeps the midpoint. Tested in ResultMarkLayoutTests.focusHeightFollowsTheMark (9a0e275).
  • The outline sits one step above the top clearance zone, however many zones there are. The card keeps its 2 cm minimum, so a result with up to four zones looks the same as before.
  • The dashed outline builder moved out of ResultScene3D into a shared FootprintOutline, which the AR model also uses. workingSpaceOutcome moved onto ResultPresentation.
  • Mark choice, focus spot, zone stacking, outline lift and dash layout live in HouseScanKit ResultMarkLayout, tested in ResultMarkLayoutTests. One behavior change in the dashes: an edge between 0.16 m and 0.2 m used to get two overlapping 0.1 m dashes. It now gets one solid line, which looks the same.
  • New HouseScanKit ResultCardActions picks the card's filled button from the answer, the spot and whether the camera is still up. offersView(capturable:sourceAvailable:) gates the card's "Show me", every check line's "Show me" and Details' "Capture it now". With the camera gone none of them shows, the same as the AR button. "Scan another wall" stays, because it starts a new camera session. ScanEngine.captureMissing also returns early when spatialResultAvailable is false. Tested in ResultCardActionsTests.
  • 6e8403f merges origin/beta into the branch. The merge was needed: git merge-tree of 0964ecc with origin/beta conflicted in ResultScreen.swift. The resolution keeps beta's spot-refused notice and its new start-over hint, and passes the card the new sourceAvailable parameter.

None of this changes placement coordinates, outcomes or the answer the card leads with.

Known gaps

  • Capturable missing evidence without a linked check (bot 4114320395) is not changed. That evidence still appears only in Details, which has its own capture button (now also gated on the source), and never becomes the primary "Show me" action. Promoting it would change ResultReading.answer: the headline would become "One more look" for a view that isn't known to settle any check. That is a product decision, so this PR leaves it open.
  • After the camera fails, a "One more look" result shows no filled button, so the card has no primary action while its headline still says one more look would settle it. No copy yet says the camera is unavailable.
  • ios: review follow-ups for #132 (AR double draw, result chevron, aim legend contrast) #137 is merged into beta, and this head contains it. Its ResultARScreen.swift edits (in SpotDirection) merged cleanly with the title, label and BatteryOverlay hunks here.
  • I haven't yet looked on a phone at an unclean spot in AR, or at a result after a camera failure. The UI tests' resultAR demo state shows a clean spot, and no UI test drives the camera-failed result.

Tests

  • Mac mini ~/hs-ci/ci-local.sh t3/110-result-details-followups g4-tf1 at 9a0e275 (the head): the xcodegen drift check passed. HouseScanKit swift test with -warnings-as-errors passed: 526 tests in 77 suites, including focusHeightFollowsTheMark. The device build passed. UI tests are pending (waiting for the Mac mini's UI lock).
  • Mac mini ~/hs-ci/ci-local.sh t3/110-result-details-followups g4-result-details-r2 at 6e8403f: the xcodegen drift check passed. HouseScanKit swift test with -warnings-as-errors passed: 525 tests in 77 suites, including ResultCardActionsTests and ResultMarkLayoutTests. The device build passed. UI tests are pending. They're waiting for the Mac mini's UI lock, and they'll also run on GitHub CI once the PR is ready.
  • Earlier run, before the Show me gating and the beta merge: g4-result-details-r1 at b8b3c37 passed everything, including UI tests (24 run, 1 skipped, 0 failures). It skips the accessibility audit.
  • git merge-tree --write-tree origin/beta HEAD at 6e8403f: clean. origin/beta (6bc1df0) is an ancestor of the head.

🤖 Generated with Claude Code

…lift)

- ResultScene3D faces the camera at the closest spot tried when there is
  no spot, the same spot it circles, so a rejected candidate round a
  corner opens from its front rather than the meter wall's heading.
- "See it on your wall" draws a spot that isn't a clean fit as the dashed
  outline of its footprint, in both the AR scene and the Canvas overlay,
  as the result card does, and no longer titles it "Your battery could go
  here" on a pass.
- The footprint outline sits above every clearance zone drawn, not at a
  fixed 2 cm that a sixth zone reached.

The mark choice, focus spot, zone stacking, outline lift and dash layout
live in HouseScanKit's ResultMarkLayout with tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 6f6e8050-ab35-42a1-b3c1-bb8132fc80a4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the size:L 100-499 effective changed lines. label Sep 27, 2026
AidenJohnston and others added 2 commits September 27, 2026 04:10
After the camera failed post-upload, the AR button was gated but the card's "Show me", the check lines' "Show me" and Details' "Capture it now" stayed on offer and opened a capture with no frames. ResultCardActions in HouseScanKit now picks the card's button and gates every capture offer on the source, and captureMissing refuses once the source is lost. Part of #110.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Resolves ResultScreen.swift: beta's spot-refused notice and start-over hint kept, with the card's sourceAvailable parameter.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@AidenJohnston
AidenJohnston marked this pull request as ready for review September 27, 2026 09:25
@codemetrics-ai

Copy link
Copy Markdown

Note

Review skipped

Codemetrics is installed on this repository, but it hasn't been added to your team yet.

To enable AI code reviews for this repo, go to your dashboard and add house-scanning-master to your team's repositories.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6e8403fd18

ℹ️ 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".

root.addChild(joint)
}
if let spot = result.spot {
if let spot = result.spot, ResultMarkLayout.spotMark(spotIsClean: result.spotIsClean) == .outline {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Aim AR visibility checks at the footprint outline

For an unclean spot, this branch moves the only spot mark to the ground, but ScanEngine.showResultInCamera and SpotDirection still test spotCenter(on:) at half the battery height. When that midpoint is inside the viewport while the ground footprint is below it, resultIsDrawn() suppresses the Canvas fallback and the chevron remains hidden, leaving the user with no visible indication of the spot. Use the footprint's ground-level center for the visibility and direction targets when rendering an outline.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AidenJohnston Independent nine-file review and lead source tracing confirm this at 6e8403f. Both renderers now put an unclean spot outline near ground level, while ResultARScreen.spotCenter:88-91 and ScanEngine:1488 retain half-battery-height focus. With that midpoint inside the clear band and the footprint below the screen or controls, neither the mark nor a downward chevron is visible. This affects Canvas on non-LiDAR too; restoring Canvas alone is insufficient. Please make the shared visibility/direction target follow the rendered mark, retaining midpoint targeting for clean batteries, and cover both projections. The clean resultAR demo does not exercise this case. Source verified only; no physical reproduction here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9a0e275. ResultMarkLayout.focusHeight(mark:batteryHeight:) (HouseScanKit) gives the height the AR view aims at: the battery middle for a clean spot, the ground for an outline. ResultPresentation.spotCenter(on:) now uses it with spotMark(spotIsClean:), so both the edge chevron (SpotDirection, Canvas and RealityKit paths alike) and ScanEngine.showResultInCamera's focus for resultIsDrawn() follow the rendered mark. Clean batteries keep the midpoint. ResultMarkLayoutTests.focusHeightFollowsTheMark covers the helper.

For a spot that isn't a clean fit both renderers draw the footprint
outline on the ground, but the edge chevron (SpotDirection) and the AR
scene's in-view check (showResultInCamera focus) still aimed at half the
battery height. With that midpoint on screen and the outline below it,
neither the mark nor the chevron showed. ResultMarkLayout.focusHeight now
gives the height for the mark drawn (battery middle or the ground), and
spotCenter uses it, so both checks follow the rendered mark.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@AidenJohnston
AidenJohnston merged commit 7bed770 into beta Sep 27, 2026
4 of 5 checks passed
SamGu-NRX pushed a commit that referenced this pull request Oct 15, 2026
retake_request is the only final event when views or a member action are needed; otherwise verdict_ready. A no-meter or degraded run that still needs views stays needs_views, and the final-event check runs on those branches too.

Co-authored-by: hss-cloud-agent <hss-cloud-agent@users.noreply.github.com>
SamGu-NRX added a commit that referenced this pull request Oct 15, 2026
Brings in all 127 commits of house-scanning-server main up to d43d657
("Emit one final event and keep result status with the outcome (#146)"),
with paths rewritten under backend/ by git filter-repo. The .github/
workflows stay out, as in the snapshot, because GitHub only runs workflows
from the repository root. Hunter's work email is mapped to his GitHub
no-reply address so this public repository doesn't publish it; GitHub
still attributes the commits to huntertcarver.

The resulting tree equals the snapshot commit 2d0911f exactly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 effective changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants