Skip to content

fix(ios): the result card names the review line, draws no unsized zones, and promises a photo only when it offers one (on #191) - #209

Open
SamGu-NRX wants to merge 7 commits into
codex/public-assembly-20260930from
fix/result-clarity
Open

SamGu-NRX wants to merge 7 commits into
codex/public-assembly-20260930from
fix/result-clarity

Conversation

@SamGu-NRX

@SamGu-NRX SamGu-NRX commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Stacked on #191 (codex/public-assembly-20260930, 75f6c37), alongside #207 and #208. This PR adds 1e45aba through 55fb4b4 (seven commits).

What changed

Three places where the result screen said more than the server's answer supports, or less than it needs to. These were findings B-13 and B-14, plus one root found after the spot-check change.

No floor zones without a battery size (B-13)

A sweep run's start_ft is a range of battery left edges, and the server sizes the battery only on spot or nearest_considered (result.schema.json). With neither, the app drew each run 0 m wide past its starts and 0.3 m deep (ScanEngine+Export.swift at 75f6c377), which is a footprint nothing measured. ResultMarkLayout.sweepZones now returns no zones without a size. With a spot or nearest spot, its zones are exactly what the old code drew. The 3D view, the AR view and the overlay all draw only those zones, so none of them changed.

The card says why a measurement inside the maximum still needs review (B-14)

The server sends review_threshold_ft on a check whose confident limit is tighter than its maximum: a cable run of 16 ft is under the 20 ft maximum and over the 15 ft confident reach (solver.py). The app dropped the field while decoding, so the card read "Measured 16 ft. The rule is at most 20 ft…" under "Not sure yet", with no reason given.

  • The field is decoded when present, written back only when present, and mapped onto CheckRow.
  • PlacementCheck.reviewBandApplies decides in the server's feet whether the review line explains this check: an unsure outcome, both thresholds, the line inside the limit, and the measurement past the line in the rule's direction. Any missing field means no.
  • The card line, its spoken value and Details now read: "Measured 16 ft. The rule is at most 20 ft, and anything 15 ft or more needs an installer's review. The measurement can be off by about 6 in."
  • It says review is needed. It never says anyone was sent, told or scheduled anything. The app contacts nobody.
  • The server's outcome is never recomputed. Without a review threshold the wording is unchanged.

An unsure line promises a photo only when it offers the camera

The unsure line said "One more photo would settle this" whenever no person had to judge the check, even when the line offered no way to take that photo. That happened after the spot check withdrew its front-space request. The line's "Show me" already depended on whether the settling view could be taken. Now the words, the spoken value, the button and the Details note all come from one fact, ResultCardActions.lineOffersView via ResultPresentation.offeredView. Without a photo to take, the line reads "Needs an installer to check", which is what Details already said for such views. Every line that offered "Show me" before still does.

UI changes

From ResultCardUITests on the iPhone 17 Simulator at f0c271c. The before for the photo promise is from #206's run 37112742785. No before exists for the review band, since no fixture had one at 75f6c37. Its before wording is quoted above.

A line promises a photo only when it offers one

Before (#206's run 37112742785) After
Before: Clear space in front reads One more photo would settle this, with no Show me After: Ground under the spot keeps One more photo and Show me; Clear space in front reads Needs an installer to check

The review line on the card, default and largest text size

Default, at 55fb4b4 Largest accessibility size, at f0c271c (before the wording fix: "over 15 ft")
<img src="https://github.com/user-attachments/assets/e965d1e5-80b1-42b3-ad74-3d0df6a73fdf" width="280" alt="Cable run length reads: Measured 16 ft. The rule is at most 20 ft, and anything 15 ft or more needs an installer's review." (55fb4b4)> The same sentence at the largest text size

No spot and no nearest spot: no floor zones

Card Details
Not on this wall, with the wall and no floor zones drawn Details with the summary

Verification

  • Pull-request run 37126344528 on 55fb4b4: 664 package tests in 93 suites passed, and 63 UI tests ran with 1 skipped and 0 failures, all seven ResultCardUITests included.

  • 55fb4b4 (review, Codex): the review line's wording is inclusive, "anything 15 ft or more" / "anything 4 ft or less". A confident pass needs measured + error < review_threshold_ft, so a value exactly on the line already needs review. reviewBandApplies was already inclusive.

  • Hosted full run 37117545464 on f0c271c: 664 package tests in 93 suites passed, and 64 UI tests ran with 1 skipped and 0 failures, including all seven ResultCardUITests and InstallerReviewUITests.

  • Package tests: ResultMarkLayoutTests (no size gives no zones; a sized run matches the old span and depth), ReviewBandTests (decoding, round trip, schema, and 18 cases of reviewBandApplies, including exact boundaries and an at-least check), ResultCardActionsTests (every combination for lineOffersView), and ResultReadingTests over the three new fixtures.

  • The new fixtures no-spot-no-nearest.json, review-band.json and view-not-offered.json validate against result.schema.json in the package suite.

  • ResultCardUITests runs at default size and the largest accessibility size. It checks the labels, the spoken values, that no handoff words appear, and that a line without a photo isn't a button.

  • Review: two reviews found three issues.

    • The implementer's reviewer caught a Float rounding error that dropped the explanation exactly on the 15 ft line, fixed in 23e05a6.
    • A fresh Sol review of the branch found that the new fixtures changed the generated Xcode project, and that the scroll helper could overshoot at the largest text size. f0c271c fixes both.
  • Local runs: none. The shared Mac's QA queue is on a safety hold, so the hosted runs are the only execution.

Risk

  • No test can see inside the 3D scene. "No zone drawn" is covered by the package function and the mapping that feeds the scene.
  • The no-spot fixture has the right shape for an answer with everything out of reach, but the solver couldn't produce it exactly.
  • Details still shows the server's reason for the cable check, which says the policy sends the result to a person. That text is the server team's. The card doesn't use it.
  • A result with no spot explains itself only through the headline and the summary under Details. Adding a reason line was outside this change.

Checklist

  • The scope is focused; related changes belong together
  • I explained what changed and why
  • UI changes have captures
  • N/A video: no motion changes.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Unsure results can now show a review range when a measurement falls within it, with the measurement uncertainty presented separately.
    • Results now offer a follow-up photo only when it’s available; otherwise, they indicate when an installer needs to check.
  • Improvements
    • Sweep-clearance markings now reflect the available spot dimensions and are omitted when dimensions aren’t available.

SamGu-NRX and others added 6 commits October 3, 2026 05:13
The sweep's start_ft is a range of battery left edges, not a footprint, and
the answer sizes a battery only on spot or nearest_considered. With neither,
the app drew each run with a width of 0 and a made-up 0.3 m depth.
ResultMarkLayout.sweepZones now gives no zones without a size, and gives
the same zones as before with one. The wall, summary and reasons stay.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…r's review

The answer's optional review_threshold_ft was dropped at decoding, so a run
of 16 ft read "The rule is at most 20 ft" under "Not sure yet", with nothing
about the 15 ft line that made it unsure. PlacementCheck now decodes the
line and writes it back only when present, CheckRow carries it, and the
measurement sentence names it when ResultReading.reviewBandApplies says it
explains an unsure outcome. The card line and its spoken value come from the
same function. The sentence says what the rule needs and never that a review
was sent.

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

ResultCardUITests reads review-band, unsure-view and no-spot-no-nearest from
Fixtures/results through the demo. It checks the cable run line's spoken
sentence, that a check without a review line keeps its old sentence, and
that an answer with neither spot shows no spot, no check lines and its
summary under Details. The review band and the no-spot answer run at the
default and the largest text size, with screenshots kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ScanCopy decided it from CheckRow's Float meters, and narrowing can move a
value across the line: 14.5 ft plus 6 in reaches 15 ft exactly, but the
same sum in Float meters fell just under it, so the card would have left
the review line out. PlacementCheck.reviewBandApplies now decides on the
decoded feet, and the mapping carries the answer on CheckRow.

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

On the spot-unknown run, "Clear space in front" read "One more photo would
settle this" after its request was withdrawn, with no way to take the photo.
The note was keyed on needsPerson alone. ResultCardActions.lineOffersView
now decides whether a line offers its settling view, and
ResultPresentation.offeredView applies it. The line's "Show me", its words
on the card and its note under Details all read that one fact. A line with
no view to take says "Needs an installer to check".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ard in measured steps

Review of d672973: XcodeGen lists every result fixture as a membership exception,
so the three new fixtures changed the generated project and CI's drift check
failed (run 37117085378). Regenerated with XcodeGen 2.46.0, checksum-verified
against ios.yml.

`scrollIntoView` swiped up a fixed amount until the line fit. At the largest
text size a tall line could jump from below the window to above it, and further
swipes up could never bring it back. Each drag now moves the content by what is
missing, at most a third of the window, toward the line.

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

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

🧰 Additional context used
📚 Code guidelines (1)
ios/README.md — configured

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2742f1cd-082d-41e4-a87c-13a9ed982afd
📥 Commits

Reviewing files that changed from the base of the PR and between 75f6c37 and 55fb4b4.

📒 Files selected for processing (18)
  • ios/HouseScan.xcodeproj/project.pbxproj
  • ios/HouseScan/Contract/ResultPresentation+Reading.swift
  • ios/HouseScan/Contract/ScanContract.swift
  • ios/HouseScan/Runtime/ScanEngine+Export.swift
  • ios/HouseScan/UI/Copy/ScanCopy.swift
  • ios/HouseScan/UI/Screens/ResultScreen.swift
  • ios/HouseScanKit/Sources/HouseScanKit/Scene/PlacementResult.swift
  • ios/HouseScanKit/Sources/HouseScanKit/Scene/ResultCardActions.swift
  • ios/HouseScanKit/Sources/HouseScanKit/Scene/ResultMarkLayout.swift
  • ios/HouseScanKit/Sources/HouseScanKit/Scene/ResultReading.swift
  • ios/HouseScanKit/Tests/HouseScanKitTests/ResultCardActionsTests.swift
  • ios/HouseScanKit/Tests/HouseScanKitTests/ResultMarkLayoutTests.swift
  • ios/HouseScanKit/Tests/HouseScanKitTests/ResultReadingTests.swift
  • ios/HouseScanKit/Tests/HouseScanKitTests/ReviewBandTests.swift
  • ios/HouseScanUITests/Fixtures/results/no-spot-no-nearest.json
  • ios/HouseScanUITests/Fixtures/results/review-band.json
  • ios/HouseScanUITests/Fixtures/results/view-not-offered.json
  • ios/HouseScanUITests/ResultCardUITests.swift

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The changes add review-band data and wording for unsure checks, align camera offers and result-card text with camera availability, and calculate sweep clearance zones from spot dimensions. New fixtures and tests cover these behaviors and results with no selected or nearest spot.

Changes

Result presentation

Layer / File(s) Summary
Review threshold decoding and evaluation
ios/HouseScanKit/Sources/HouseScanKit/Scene/PlacementResult.swift, ios/HouseScanKit/Sources/HouseScanKit/Scene/ResultReading.swift, ios/HouseScan/Contract/ScanContract.swift, ios/HouseScan/UI/Copy/ScanCopy.swift, ios/HouseScanKit/Tests/HouseScanKitTests/ReviewBandTests.swift, ios/HouseScanUITests/Fixtures/results/review-band.json, ios/HouseScanUITests/ResultCardUITests.swift
Placement checks decode an optional review threshold and calculate whether an unsure measurement falls within its review band. Result-card copy and tests cover review-band wording and measurements.
Camera offer rules and result-card integration
ios/HouseScanKit/Sources/HouseScanKit/Scene/ResultCardActions.swift, ios/HouseScan/Contract/ResultPresentation+Reading.swift, ios/HouseScan/UI/Copy/ScanCopy.swift, ios/HouseScan/UI/Screens/ResultScreen.swift, ios/HouseScanKit/Tests/HouseScanKitTests/ResultCardActionsTests.swift, ios/HouseScanUITests/Fixtures/results/view-not-offered.json, ios/HouseScanUITests/ResultCardUITests.swift, ios/HouseScan.xcodeproj/project.pbxproj
Camera offers require an unsure check, no person requirement, a capturable settling view, and an available source. Result-card actions, text, and Details accessibility values use the offer decision. Fixtures and UI tests cover offered and unavailable views.
Sweep clearance zones and empty-placement results
ios/HouseScanKit/Sources/HouseScanKit/Scene/ResultMarkLayout.swift, ios/HouseScan/Runtime/ScanEngine+Export.swift, ios/HouseScanKit/Tests/HouseScanKitTests/ResultMarkLayoutTests.swift, ios/HouseScanKit/Tests/HouseScanKitTests/ResultReadingTests.swift, ios/HouseScanUITests/Fixtures/results/no-spot-no-nearest.json, ios/HouseScanUITests/ResultCardUITests.swift
Sweep zones use battery width and depth and are omitted when battery dimensions are unavailable. Tests cover zone spans and results with no spot or nearest candidate.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Suggested reviewers: aidenjohnston

Merge Risk: ⚪ Minimal · up to 55fb4

The change makes result-card wording, photo offers, and clearance zones consistent with the data available. No concrete merge-blocking risk was identified; the author's hosted test runs passed.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 55fb4

The reviewed changes preserve server decisions and existing camera safeguards. No introduced security issue was identified, but the available coverage does not support a complete end-to-end security assessment.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The inspected changes affect result interpretation, displayed geometry, and photo-offer presentation within the app. They do not demonstrate increased authority beyond the existing result-driven capture path.

Trust Boundaries and Controls

  • observed — Presentation eligibility does not execute capture directly. The UI routes the offered evidence ID through captureMissing, which independently validates allowed phase, camera availability, evidence identity, coverage, and a valid gap plan before initiating capture.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.82% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 55 functions across 14 files. (4 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the three main result-card changes. It is longer than ideal, but remains specific and relevant.
Description check ✅ Passed The description explains the changes and rationale, includes UI captures, reports verification results and limits, and covers risk and checklist items. The required “Why” section heading is absent, bu…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 61.82% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 55 functions across 14 files. (4 skipped: 4 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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:XL 500-999 effective changed lines. label Oct 3, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-03T12:12:10.789552Z f0c271c PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@codemetrics-ai

codemetrics-ai Bot commented Oct 3, 2026

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 BaseScanning to your team's repositories.

@greptile-apps

greptile-apps Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 3/5

[Medium risk] Refines how the result card displays checks and zones.

The PR does not appear safe to merge while the review-line explanation and camera-failure guidance remain misleading.

Fix All in CodexFindings

  1. P1 Review line misstates uncertainty ▶
  2. P1 Camera failure implies installer needed ▶
  3. P2 No-zone test misses zones ▶
Fix with agent prompt
### Issue 1
ios/HouseScanKit/Sources/HouseScanKit/Scene/ResultReading.swift:100-104
When a 14.5 ft cable run has ± 0.5 ft of error, this check treats the 15 ft review line as applicable even though the measured value is not over it. The card then says that “anything over 15 ft needs an installer’s review,” which does not explain why this result is unsure. The same wording appears when the measurement is uncertain near the 20 ft maximum, where the server gives a different reason. Please account for the measurement’s error and the server’s reason when choosing the explanation.

### Issue 2
ios/HouseScan/UI/Copy/ScanCopy.swift:703-707
If the camera fails after upload, a check that could otherwise be settled by a photo has no offered photo, so this note changes to “Needs an installer to check.” The check does not require a person to judge it, and the headline still says “One more look.” This gives the homeowner a false installer requirement instead of explaining that capture is unavailable.

### Issue 3
ios/HouseScanUITests/ResultCardUITests.swift:119-130
This test checks that there is no battery spot and that the wall model exists, but it never checks whether clearance zones are present. The separate package test covers `sweepZones` alone, so a regression in the export mapping could restore unsized floor zones while both tests still pass. Checking the resulting clearance list would cover the behavior this test names.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Summary

This PR suppresses floor zones when the server supplies no battery size, adds the server’s review threshold to result-card wording, and ties photo wording to whether the card offers a camera action. It also adds package fixtures and UI coverage. The earlier review findings remain outstanding.

Reviews (2) · Last reviewed commit: "ios: the review line's wording includes ..."

Comment on lines +100 to +104
guard outcome == .unsure, let measured, let threshold, let reviewThreshold, let comparison else { return false }
let error = max(plusMinus ?? 0, 0)
switch comparison {
case .atMost: return reviewThreshold < threshold && !(measured + error < reviewThreshold)
case .atLeast: return reviewThreshold > threshold && !(measured - error > reviewThreshold)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Review line misstates uncertainty When a 14.5 ft cable run has ± 0.5 ft of error, this check treats the 15 ft review line as applicable even though the measured value is not over it. The card then says that “anything over 15 ft needs an installer’s review,” which does not explain why this result is unsure. The same wording appears when the measurement is uncertain near the 20 ft maximum, where the server gives a different reason. Please account for the measurement’s error and the server’s reason when choosing the explanation.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ios/HouseScanKit/Sources/HouseScanKit/Scene/ResultReading.swift
Line: 100-104

Comment:
**Review line misstates uncertainty** When a 14.5 ft cable run has ± 0.5 ft of error, this check treats the 15 ft review line as applicable even though the measured value is not over it. The card then says that “anything over 15 ft needs an installer’s review,” which does not explain why this result is unsure. The same wording appears when the measurement is uncertain near the 20 ft maximum, where the server gives a different reason. Please account for the measurement’s error and the server’s reason when choosing the explanation.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex Fix in Claude Code

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

The decision follows the server's rule: the band applies when measured + error is not below the review line, so 14.5 ft ± 6 in is unsure because it can reach 15 ft. With 55fb4b4 the card reads "Measured 14 ft 6 in. The rule is at most 20 ft, and anything 15 ft or more needs an installer's review. The measurement can be off by about 6 in." Together those two sentences are the reason: the run can reach the line. Near the 20 ft maximum the same sentences stay true, and the error sentence carries the margin. The server's own reason is unchanged under Details. The client doesn't switch wording on unsure_cause, since that would mean restating the server's outcome logic on the phone.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

That clarification resolves the concern. The inclusive boundary is consistent with the server/schema rule: at_most only clears the review line when measured + error < reviewThresholdFt, so 14.5 ft ± 0.5 ft correctly reaches the 15 ft line and the review-band wording applies. Reading the values in feet also avoids changing that boundary through Float conversion. The updated “15 ft or more” wording accurately describes the inclusive rule, and keeping the server’s unsure_cause out of the client explanation is reasonable since the client is not recomputing or replacing the server’s outcome. I no longer consider this a valid finding.

Comment on lines +703 to +707
/// Who settles an unsure check. One more photo only when the app offers the camera for it
/// (`ResultPresentation.offeredView`): keyed on the check alone, a view the homeowner
/// couldn't get to, or one the app can't plan, still promised a photo nothing would take.
static func unsureNote(photoOffered: Bool) -> String {
photoOffered ? Self.onePhoto : Self.needsInstaller

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Camera failure implies installer needed If the camera fails after upload, a check that could otherwise be settled by a photo has no offered photo, so this note changes to “Needs an installer to check.” The check does not require a person to judge it, and the headline still says “One more look.” This gives the homeowner a false installer requirement instead of explaining that capture is unavailable.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ios/HouseScan/UI/Copy/ScanCopy.swift
Line: 703-707

Comment:
**Camera failure implies installer needed** If the camera fails after upload, a check that could otherwise be settled by a photo has no offered photo, so this note changes to “Needs an installer to check.” The check does not require a person to judge it, and the headline still says “One more look.” This gives the homeowner a false installer requirement instead of explaining that capture is unavailable.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex Fix in Claude Code

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Intended, per the brief this PR implements: a line must not promise that a photo will settle the check when the app won't take that photo. After the camera fails, the result offers no capture for the rest of this session, so the photo line would be a promise nothing can keep. "Needs an installer to check" is the same wording Details already used for views it can't offer, at 75f6c37 and before. It says a check is still needed, not that one was arranged. The headline and the notes come from the server's outcome and aren't recomputed here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

That’s fair, and the brief makes this behavior intentional: after capture failure, the app no longer offers a photo, so “One more photo would settle this” would be an unfulfillable promise. “Needs an installer to check” describes the remaining action without implying that anyone was contacted or that the server outcome was recomputed. I’m withdrawing this finding.

Comment on lines +119 to +130
XCTAssertEqual(element(app, "result.headline").label, "Not on this wall")
XCTAssertFalse(element(app, "result.placement").exists)
XCTAssertFalse(element(app, "result.nearest").exists)
let checkLines = app.descendants(matching: .any).matching(NSPredicate(format: "identifier BEGINSWITH 'check.'"))
XCTAssertEqual(checkLines.count, 0, "an answer without checks put check lines on the card")
let model = app.descendants(matching: .any).matching(NSPredicate(format: "label == '3D view of your wall'")).firstMatch
XCTAssertTrue(model.waitForExistence(timeout: 10), "the model of the wall is missing")
XCTAssertEqual(value(model), "No battery spot shown")
attach(app, name: name)

let details = element(app, "result.details")
scrollIntoView(details, in: app)

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 No-zone test misses zones This test checks that there is no battery spot and that the wall model exists, but it never checks whether clearance zones are present. The separate package test covers sweepZones alone, so a regression in the export mapping could restore unsized floor zones while both tests still pass. Checking the resulting clearance list would cover the behavior this test names.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ios/HouseScanUITests/ResultCardUITests.swift
Line: 119-130

Comment:
**No-zone test misses zones** This test checks that there is no battery spot and that the wall model exists, but it never checks whether clearance zones are present. The separate package test covers `sweepZones` alone, so a regression in the export mapping could restore unsized floor zones while both tests still pass. Checking the resulting clearance list would cover the behavior this test names.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex Fix in Claude Code

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

The 3D scene isn't inspectable from a UI test: RealityKit entities don't appear in the accessibility tree, and the zones have no accessible element. So "no zone drawn" rests on ResultMarkLayout.sweepZones (package tests) and the one-line mapping in ScanEngine+Export that feeds every zone consumer. The PR's Risk section says this. A UI-visible proxy would mean adding an accessibility element only for tests, which I'd rather not ship.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You're right—the 3D scene and its zone entities aren't exposed through the UI accessibility tree, so this UI test cannot meaningfully verify whether zones are drawn without adding test-only production accessibility surface. Since ResultMarkLayout.sweepZones is covered directly and the single export mapping feeds the 3D, AR, and overlay consumers, the package tests plus mapping coverage are appropriate here. I’m withdrawing this comment; the existing Risk section accurately documents the remaining limitation.

SamGu-NRX added a commit that referenced this pull request Oct 3, 2026
… the result card names the review line, draws no unsized zones, and promises a photo only when it offers one

project.pbxproj conflicted only in the generated fixture exception lists (#206's and #209's new result fixtures); it is regenerated with XcodeGen 2.46.0 from the merged tree.

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

@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: f0c271cfb6

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

Comment thread ios/HouseScan/UI/Copy/ScanCopy.swift Outdated
Comment on lines +747 to +748
case .atMost: "anything over \(length(review))"
case .atLeast: "anything under \(length(review))"

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 Include equality in the review-band wording

When an at-most measurement plus its error equals reviewThreshold, the server returns UNSURE because passing requires <, and reviewBandApplies also returns true, but this text says only values “over” the threshold need review. The mirrored at-least branch likewise says “under” even though equality also needs review. Use inclusive wording such as “15 ft or more” and “4 ft or less” so the displayed answer matches the rule boundary.

AGENTS.md reference: AGENTS.md:L32-L34

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Right. Fixed in 55fb4b4. For an at-most check, a confident pass needs measured + error < review_threshold_ft, so a value exactly on the line already needs review. The card now says "anything 15 ft or more" under a maximum and "anything 4 ft or less" over a minimum. reviewBandApplies was already inclusive, so only the words changed.

Review of #209 (Codex): a confident pass needs measured + error < review_threshold_ft
for an at-most check (result.schema.json, solver.py reach_outcome), so a run landing
exactly on 15 ft already needs review, and "anything over 15 ft" left that case out.
The card now says "anything 15 ft or more" under a maximum and "anything 4 ft or less"
over a minimum. The decision (`reviewBandApplies`) was already inclusive; only the
words change.

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

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

SamGu-NRX added a commit that referenced this pull request Oct 3, 2026
… the review line's wording includes the line itself

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

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 effective changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant