Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
ca98508
chore(review): run Greptile again when PR commits change
SamGu-NRX Oct 1, 2026
c813182
Merge pull request #194 from SamGu-NRX/codex/greptile-push-reviews-20…
SamGu-NRX Oct 1, 2026
4a24cd5
Prepare homeowner follow-ups on the tested candidate
SamGu-NRX Oct 3, 2026
6ec4016
ios: Start over keeps a scan whose bundle is still being written
SamGu-NRX Oct 3, 2026
3e75514
Show a passing spot as a possible spot, not a fit
SamGu-NRX Oct 3, 2026
1b7209f
Read a pass without a spot or passing checks as installer review
SamGu-NRX Oct 3, 2026
ab7b582
Keep fit claims out of every result's summary and footnotes
SamGu-NRX Oct 3, 2026
2d39637
ios: the rapid Start over test reads which cleanup each write released
SamGu-NRX Oct 3, 2026
a7c2a64
ios: the README says a scan started over reaches Saved scans only if …
SamGu-NRX Oct 3, 2026
12cf77f
Capture the real candidate's AR instruction at the largest text size
SamGu-NRX Oct 3, 2026
8e9b07c
Leave unsure_cause out of the tests' passing answers
SamGu-NRX Oct 3, 2026
a7c65bd
ios: a past-end request can mark the real wall end; inferred ends say…
SamGu-NRX Oct 4, 2026
f4c3e17
ios: the too-short end is refused by the aim check the preview shares…
SamGu-NRX Oct 4, 2026
a76ba4d
ios: the B44 cleanup tests allow five minutes before a hang fails them
SamGu-NRX Oct 4, 2026
63bf4e7
ios: a tracking change republishes the end preview, so a pose-only fr…
SamGu-NRX Oct 4, 2026
448c45a
ios: the provenance tests expect the inferred end's shape and refuse …
SamGu-NRX Oct 4, 2026
15cf658
ios: a corner marked on a past-end request closes it cannot_reach, an…
SamGu-NRX Oct 4, 2026
c9295df
Take the first match for each identifier in the provisional-placement…
SamGu-NRX Oct 4, 2026
a7b4ec3
Fold the AR card at the largest text sizes while the spot is in view
SamGu-NRX Oct 4, 2026
0fb7380
Measure the AR camera window from the card's bottom, clipped to the s…
SamGu-NRX Oct 4, 2026
21ac61e
ios: at the largest text sizes, the wall-end card folds so the circle…
SamGu-NRX Oct 4, 2026
254a456
ios: folded end cards keep coaching off the circle, and the moved rep…
SamGu-NRX Oct 4, 2026
b1dc252
ios: folded end cards lead with the remedy for darkness, and with the…
SamGu-NRX Oct 4, 2026
f8ccc29
Integrate tested active-archive retention repair
SamGu-NRX Oct 4, 2026
577a683
Integrate tested provisional-placement result and AR fold
SamGu-NRX Oct 4, 2026
55449e3
ios: the past-end circle is in the view only while offered, so VoiceO…
SamGu-NRX Oct 4, 2026
6a5b240
ios: the coached fold tests look for the note's words, not the lead's
SamGu-NRX Oct 4, 2026
7d324dc
Integrate tested past-end recovery for the next app work
SamGu-NRX Oct 4, 2026
87acda4
Import PR #192's capture packet 0.4, uploader and result client
SamGu-NRX Oct 4, 2026
3c20ac2
Add a scan context and photo-processing controller to HouseScanKit
SamGu-NRX Oct 4, 2026
7f52e09
Route photo-processing scans through their own engine path and screen
SamGu-NRX Oct 4, 2026
4a48e22
Test the photo-processing path in the app and document it
SamGu-NRX Oct 4, 2026
6b1a1ee
Integrate tested wall-end aiming visibility
SamGu-NRX Oct 4, 2026
0861fa4
Attach the capture API's credential only inside its configured scope
SamGu-NRX Oct 4, 2026
5120284
End an upload refused at the credential boundary, without retrying it
SamGu-NRX Oct 4, 2026
73e06d7
Send nothing for a request cancelled while its credential is fetched
SamGu-NRX Oct 4, 2026
12e4fa2
Add a labelled synthetic capture and say what an answer's match proves
SamGu-NRX Oct 4, 2026
24efd35
Run photo processing in-app on the synthetic capture; stop unrunnable…
SamGu-NRX Oct 4, 2026
b708de3
Combine the tested photo-processing app path
SamGu-NRX Oct 4, 2026
6ca1bbb
Test a withdrawal while the credential provider waits and then returns
SamGu-NRX Oct 4, 2026
3ae118f
Read any transport error after a withdrawal as the withdrawal
SamGu-NRX Oct 4, 2026
2e08c88
Log a withdrawal that overtakes an error, and test the in-flight give…
SamGu-NRX Oct 4, 2026
0b3c79d
Split hosted iOS UI tests into journey and photo-processing jobs
SamGu-NRX Oct 4, 2026
0699e82
Merge capture-scoped auth (2e08c88f) into the photo-processing candidate
SamGu-NRX Oct 4, 2026
db301cb
Show capture-scoped auth refusals as one setup state
SamGu-NRX Oct 4, 2026
3df2da7
ios: the stop-sending question says only what House Scan stops doing
SamGu-NRX Oct 4, 2026
f0468d4
ios: after Stop sending or Start over, say only what House Scan stops…
SamGu-NRX Oct 4, 2026
0c68d92
Test fresh retry limits on a recreated capture and the end of an uplo…
SamGu-NRX Oct 4, 2026
9ccce0f
ios: don't seal a photo-processing capture while kept photos are stil…
SamGu-NRX Oct 4, 2026
d1d3076
Give a recreated capture fresh retry limits, and end an upload whose …
SamGu-NRX Oct 4, 2026
d63cc6e
Test that a failed save stops a request waiting for its credential, a…
SamGu-NRX Oct 4, 2026
04aeff6
Stop a waiting request when a save fails, and let a withdrawal outran…
SamGu-NRX Oct 4, 2026
135377c
Merge commit '04aeff676311404897b3c48b5802800466b59656' into codex/ph…
SamGu-NRX Oct 4, 2026
eea5f7a
ios: a scan whose upload state the phone couldn't save ends as a loca…
SamGu-NRX Oct 4, 2026
8cc8cec
ios: stop un-hiding the camera's decoration for VoiceOver when no pho…
SamGu-NRX Oct 4, 2026
e1a5cae
Record each ARFrame's intrinsics with its pose for the 0.4 pose stream
SamGu-NRX Oct 4, 2026
c3e095d
Test that settles still sees an uploader settle through a stalled tes…
SamGu-NRX Oct 4, 2026
6c1f68e
Count settles' budget in its own turns and read the answer after the …
SamGu-NRX Oct 4, 2026
ac5a512
ios: hide the screen under the photo question from accessibility only…
SamGu-NRX Oct 4, 2026
6fa43b9
Merge commit '6c1f68eade3be7cac03d123f113af4d95f8330c6' into codex/ph…
SamGu-NRX Oct 4, 2026
1be8ede
Send the accepted meter mark's own frame as the capture packet's tap
SamGu-NRX Oct 4, 2026
d4dcd96
Let MeterTapFailure be a Result's failure
SamGu-NRX Oct 4, 2026
a3d10ec
Keep a yes after a failed meter tap away from the coordinator
SamGu-NRX Oct 4, 2026
3be7f64
Test that a photo or tap the phone couldn't keep stops the capture's …
SamGu-NRX Oct 4, 2026
63f4348
Stop a capture's upload when the phone loses a photo or tap the scan …
SamGu-NRX Oct 4, 2026
f47fda3
Test that a world reset records its capture's end before newWorld ret…
SamGu-NRX Oct 4, 2026
756b86f
Record a world's end before newWorld returns, and never resume that c…
SamGu-NRX Oct 4, 2026
4fe929d
Test that a storage URL to ::1 counts as this machine and near matche…
SamGu-NRX Oct 4, 2026
22b932f
Treat a storage URL to ::1 as this machine, by the API scope's own rule
SamGu-NRX Oct 4, 2026
7f80a19
Make inputLostCode readable outside the main actor
SamGu-NRX Oct 4, 2026
91b673a
Test a withdrawal after a loss, a reset after an unrecorded withdrawa…
SamGu-NRX Oct 4, 2026
0d6e292
Let a withdrawal outrank a lost input, report an unrecorded no at res…
SamGu-NRX Oct 4, 2026
9f2c8a4
Merge commit '0d6e2924' into feat/input-lost-mapping-20261004
SamGu-NRX Oct 4, 2026
afd16da
End a scan whose phone lost an accepted photo or tap as not prepared
SamGu-NRX Oct 4, 2026
b0440ef
Merge the meter mark's own-frame tap (a3d10ec4) into the capture meta…
SamGu-NRX Oct 4, 2026
1cf4488
Merge per-frame camera intrinsics (e1a5cae4) into the capture metadat…
SamGu-NRX Oct 4, 2026
766bd8f
Say the live meter tap is recorded but unchecked on a phone, not missing
SamGu-NRX Oct 4, 2026
3499e65
Split the iOS UI tests into three jobs and keep a cancelled job's res…
SamGu-NRX Oct 4, 2026
e564760
Wait for the background Simulator boot before checking it
SamGu-NRX Oct 4, 2026
f6231b4
Count the photo-processing suites' waits in their own turns
SamGu-NRX Oct 4, 2026
e66226c
Mark a failed result snapshot as partial, and finish the README's liv…
SamGu-NRX Oct 4, 2026
94503ed
Fold a follow-up gap request's card at the largest text sizes
SamGu-NRX Oct 4, 2026
07be16e
Name the folded lead's side against the meter, and keep gap(_:)'s doc…
SamGu-NRX Oct 4, 2026
263827e
Scroll the Details test until "I can't get there" is wholly on screen
SamGu-NRX Oct 4, 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
84 changes: 72 additions & 12 deletions .github/workflows/ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,20 @@ concurrency:

jobs:
ios-build:
name: iOS build
# Three groups of the UI tests, one job each (ios/Tools/ui-test-groups.py holds their selectors
# and checks that together they run every test once). With two groups, journey hit the cap
# below in run 37221532164 (#216 at 6fa43b9b): 12 min of package tests and build, then a
# 75.3 min UI step that stopped after 107 of its 109 tests. That run's per-class times put
# ScreenStatesUITests at 1892 s (its every-state audit 905 s) and the other journey classes at
# about 2475 s, so ScreenStatesUITests has its own job. journey runs the package tests, the
# project check and the Debug device build; photoProcessing runs the unsigned Release build;
# screenStates runs only its UI tests. fail-fast is off so a failure in one group still leaves
# the others' results.
name: iOS build (${{ matrix.group }})
strategy:
fail-fast: false
matrix:
group: [screenStates, journey, photoProcessing]
# A free account runs 5 macOS jobs at once, shared by every open pull request, so drafts and
# labels other than full-ui don't take a slot.
if: >-
Expand All @@ -42,7 +55,9 @@ jobs:
# freshness UI tests add about 161 s more (run 36744881974), so 60 would cut the
# every-state audit short. 75 left room until the 2026-10-03 candidate's 86 UI cases:
# run 37121918073 attempt 2 spent 10 min 34 s before the UI step and 64 min 39 s in it,
# and the cap stopped it after 76 cases with 0 failures. 90 runs all of them.
# and the cap stopped it after 76 cases with 0 failures. 90 ran all of them; since photo
# processing's tests moved to their own job, 90 is the cap for each group, and the groups are
# split so that each fits it rather than raising it.
timeout-minutes: 90
env:
# Newest stable Xcode on macos-26 per images/macos/macos-26-arm64-Readme.md (image 20260907).
Expand All @@ -55,7 +70,9 @@ jobs:
XCODEGEN_VERSION: 2.46.0
XCODEGEN_SHA256: 4d9e34b62172d645eed6457cac13fc222569974098ef4ee9c3368bedf0196806
# The every-state accessibility audit relaunches the app 65 times (about 10 min). Pull
# requests skip it unless labelled full-ui; pushes and manual runs always include it.
# requests skip it unless labelled full-ui; pushes and manual runs always include it. It is
# in the screenStates group; photoProcessing always runs its own audits.
GROUP: ${{ matrix.group }}
FULL_UI: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'full-ui') }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -71,6 +88,13 @@ jobs:
xcodebuild -version
swift --version

# Before anything slow: the groups' selectors must cover every UI test exactly once, and the
# CI tools' own tests (the groups' check and the result snapshot) must pass.
- name: Check the UI test groups
run: |
python3 -m unittest discover -s ios/Tools -p 'test_*.py'
python3 ios/Tools/ui-test-groups.py check

# Booting takes 2 to 3 minutes and needs nothing from the build, so it runs alongside the
# steps below; the UI test step waits for it.
- name: Boot the Simulator in the background
Expand All @@ -86,6 +110,7 @@ jobs:
fi
echo "SIM_UDID=$udid" >> "$GITHUB_ENV"
nohup xcrun simctl bootstatus "$udid" -b > "$RUNNER_TEMP/simulator-boot.log" 2>&1 &
echo "SIM_BOOT_PID=$!" >> "$GITHUB_ENV"

# The package's drift test compares the vendored server schemas with the server's own copies:
# the checkout's files once that branch merges, else the t3/server branch, which the shallow
Expand All @@ -94,6 +119,7 @@ jobs:
# than skip, so CI can't go green without comparing. The checkout counts only when it holds
# every compared file: a folder alone isn't enough (main has a server/ without schemas).
- name: Fetch the server contract
if: matrix.group == 'journey'
run: |
fetch_unless_present() {
local branch="$1"; shift
Expand All @@ -111,6 +137,7 @@ jobs:
fetch_unless_present t3/server server/schemas/scene.schema.json server/schemas/result.schema.json server/tests/fixtures/example-scene.json

- name: Install XcodeGen
if: matrix.group == 'journey'
run: |
curl -fsSL -o "$RUNNER_TEMP/xcodegen.zip" \
"https://github.com/yonaskolb/XcodeGen/releases/download/${XCODEGEN_VERSION}/xcodegen.zip"
Expand All @@ -119,9 +146,11 @@ jobs:
echo "$RUNNER_TEMP/xcodegen/bin" >> "$GITHUB_PATH"

- name: Generate project
if: matrix.group == 'journey'
run: xcodegen generate --spec ios/project.yml

- name: Check committed project matches project.yml
if: matrix.group == 'journey'
run: |
if ! git diff --exit-code -- ios; then
echo "::error::HouseScan.xcodeproj differs from project.yml. Run 'make ios-project' (XcodeGen ${XCODEGEN_VERSION}) and commit the result."
Expand All @@ -136,42 +165,73 @@ jobs:

- name: Test HouseScanKit
# The capture logic is a plain Swift package; its tests run on macOS without a Simulator.
# Once per run: photoProcessing builds the same package sources into its Release build.
if: matrix.group == 'journey'
env:
HOUSESCAN_REQUIRE_UPSTREAM: "1"
run: swift test --package-path ios/HouseScanKit -Xswiftc -warnings-as-errors

# CI builds once from clean, so the index Xcode keeps for editing is wasted work.
- name: Build
if: matrix.group == 'journey'
run: >-
xcodebuild -project ios/HouseScan.xcodeproj -scheme HouseScan -configuration Debug
-destination "generic/platform=iOS" CODE_SIGNING_ALLOWED=NO COMPILER_INDEX_STORE_ENABLE=NO build

# Proves the Release configuration compiles, the photo-processing setup gate included, whose
# fixture switches exist only in Debug. It doesn't show what Release does at run time.
- name: Build Release, unsigned
if: matrix.group == 'photoProcessing'
run: >-
xcodebuild -project ios/HouseScan.xcodeproj -scheme HouseScan -configuration Release
-destination "generic/platform=iOS" CODE_SIGNING_ALLOWED=NO COMPILER_INDEX_STORE_ENABLE=NO build

# The background boot first: screenStates reaches this step 3 s after starting it, and a
# second `bootstatus -b` while that boot was under way exited 149 (run 37228728303). Once it
# has finished, `-b` returns at once on a booted device, and boots it if the first try failed.
- name: Wait for the Simulator
timeout-minutes: 10
run: |
xcrun simctl bootstatus "$SIM_UDID" -b
while kill -0 "$SIM_BOOT_PID" 2>/dev/null; do sleep 2; done
if ! xcrun simctl bootstatus "$SIM_UDID" -b; then
echo "::error::$SIM_NAME on iOS $SIM_OS did not boot. The background boot's log follows."
cat "$RUNNER_TEMP/simulator-boot.log"
exit 1
fi
echo "Booted $SIM_NAME on iOS $SIM_OS ($SIM_UDID)."

- name: UI test the whole flow in the Simulator
- name: UI test the group in the Simulator
# Replays the committed synthetic wall (ios/HouseScanUITests/Fixtures/synthetic-wall) with
# -autopilot and the bundled sample result.
# -autopilot and the bundled sample result; photoProcessing adds its in-app fixture.
run: |
skip=()
if [ "$FULL_UI" != "true" ]; then
skip=(-skip-testing:HouseScanUITests/ScreenStatesUITests/testEveryStatePassesTheAccessibilityAudit)
if [ "$GROUP" = screenStates ] && [ "$FULL_UI" != "true" ]; then
echo "::notice::Skipped the every-state accessibility audit (about 10 min). Add the full-ui label to run it on this pull request."
fi
# Read without mapfile: the runner's /bin/bash is 3.2.
list="$(python3 ios/Tools/ui-test-groups.py args "$GROUP" --full-ui "$FULL_UI")"
selectors=()
while IFS= read -r line; do selectors+=("$line"); done <<< "$list"
echo "Selectors: ${selectors[*]}"
xcodebuild -project ios/HouseScan.xcodeproj -scheme HouseScan -configuration Debug \
-destination "id=$SIM_UDID" \
-resultBundlePath "$RUNNER_TEMP/HouseScanUITests.xcresult" \
-only-testing:HouseScanUITests "${skip[@]}" \
"${selectors[@]}" \
COMPILER_INDEX_STORE_ENABLE=NO test

# A run the cap cancels leaves the bundle half-written, and its Staging/ files vanish while
# they are read: run 37221532164's journey upload stopped at the first one (ENOENT) and kept
# nothing. This copies the bundle first, lets only Staging/ entries vanish, and lists them in
# SNAPSHOT.txt beside it ("complete" or "incomplete"); any other error fails this step. The
# job's own result, a cancellation included, stays as it was.
- name: Snapshot the UI test results
if: always()
run: python3 ios/Tools/snapshot-xcresult.py "$RUNNER_TEMP/HouseScanUITests.xcresult" "$RUNNER_TEMP/ui-test-results"

- name: Keep UI test screenshots
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ui-test-results
path: ${{ runner.temp }}/HouseScanUITests.xcresult
name: ui-test-results-${{ matrix.group }}
path: ${{ runner.temp }}/ui-test-results
if-no-files-found: ignore
retention-days: 7
3 changes: 3 additions & 0 deletions .greptile/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"autoReview": ["open", "push"]
}
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ State what the old code did before describing the new behavior. Link the reviewe

The `size:*` label describes the effective diff. It is a review signal, not a merge gate. Do not set it by hand.

Greptile reviews new commits through [`.greptile/config.json`](.greptile/config.json). The dashboard's open-only trigger left follow-up commits unreviewed. This repository override adds push reviews without changing other repositories' settings. Greptile reads this setting from the PR's source branch, so older branches need the config too. For a branch without it, request a current review with `@greptileai review` after pushing. Use `@greptileai review this draft` for drafts.

## Checks

| Check | Runs on GitHub when | Local command |
Expand All @@ -36,6 +38,8 @@ The `size:*` label describes the effective diff. It is a review signal, not a me

The iOS UI tests skip the every-state accessibility audit on pull requests, because it adds about 10 minutes and macOS runners are scarce. Add the `full-ui` label when a pull request changes screens or copy; pushes to `t3/ios-mvf` and `main` always run it.

The iOS check runs as three jobs, each under its own 90-minute cap: `screenStates` runs `ScreenStatesUITests`, the every-state audit included under `full-ui`; `photoProcessing` runs an unsigned Release build and `PhotoProcessingUITests` with its own audits; and `journey` runs the package tests, the Debug build and every other UI test class. `ios/Tools/ui-test-groups.py` holds the groups' test selectors; `python3 ios/Tools/ui-test-groups.py check` lists the UI tests from source and fails unless the groups run each exactly once. Run it after adding or renaming a UI test class. Each job keeps its result bundle as the artifact `ui-test-results-<group>`, with `SNAPSHOT.txt` saying whether the copy is complete; a job the cap cancelled can leave it incomplete.

`make check` runs the server, web and iOS suites, then `make scoring`, `make measure-lab`, `make evals`, `make recon` and `make meter-closeup` for each of those folders the branch has. They need uv, Node 24 with pnpm, and Xcode 26 or newer; each directory's README has details. No check is required by branch rules yet. Don't call one required until the rules require its status.

Keep workflows that run pull-request code away from production credentials and destructive external systems. A green CI run is evidence for the checks it ran, not proof that a capture works on a real house.
Expand Down
14 changes: 1 addition & 13 deletions ios/HouseScan/Contract/ResultPresentation+Reading.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ extension ResultPresentation {
checks.map { row in
ResultReading.Check(
id: row.id, outcome: row.outcome.placementOutcome, needsPerson: row.needsPerson,
viewCapturable: viewToTake(for: row) != nil,
margin: ResultReading.margin(
measured: row.measured.map(Double.init), threshold: row.threshold.map(Double.init),
plusMinus: row.plusMinus.map(Double.init), comparison: row.comparison?.placementComparison)
viewCapturable: viewToTake(for: row) != nil
)
}
}
Expand All @@ -102,12 +99,3 @@ private extension CheckOutcome {
}
}
}

private extension RuleComparison {
var placementComparison: PlacementComparison {
switch self {
case .atLeast: .atLeast
case .atMost: .atMost
}
}
}
28 changes: 28 additions & 0 deletions ios/HouseScan/Contract/ScanContract.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import CoreGraphics
import Foundation
import HouseScanKit
import Observation
import simd
import SwiftUI
Expand Down Expand Up @@ -33,6 +34,9 @@ enum ScanPhase: String, Sendable, CaseIterable {
case spotConfirm
case result
case resultAR
/// A photo-processing scan after it was sent: its progress, then its answer
/// (`ScanViewState.photoProcessing`). Legacy scans never come here.
case processing
case unsupported
}

Expand Down Expand Up @@ -567,6 +571,10 @@ enum EndMarkRefusal: Error, Equatable, Sendable {
case otherSide(WallSide)
/// Tracking isn't normal, as for a feature mark (`MarkRefusal.trackingNotReady`).
case trackingNotReady
/// During a past_end request: an end there would leave less wall than the walk's minimum
/// (`CoverageMap.endWouldLeaveTooLittle`, `WallFrame.minWallLength`), which the app can't use.
/// Decided in `aimedEnd`, so the preview and the button agree.
case tooLittleWall
}

enum MarkRefusal: Equatable, Sendable {
Expand Down Expand Up @@ -631,6 +639,10 @@ struct GapRequest: Identifiable, Equatable, Sendable {
/// Set while a walk-out request's line lies past where the space ends
/// (`GapPlanner.walkOutBlock`): no walk can meet it, and the card says so.
var spaceEnds: SpaceEnds? = nil
/// A server past_end request's side: the walk stopped there, and the request asks to walk on
/// past it. The screen also offers "Wall ends here" for that end, with its question, as the
/// walk does (B-12). Nil for every other request.
var pastEndSide: WallSide? = nil
}

// MARK: - Upload and result
Expand Down Expand Up @@ -957,6 +969,14 @@ final class ScanViewState {
var shareableScan: URL?
/// A camera permission or session failure the homeowner can act on.
var failure: ScanFailure?
/// The backend this scan uses, fixed when it started; nil before a scan starts.
var scanBackend: ProcessingBackend?
/// Photo processing's side of this scan: its consent, progress and answer. Nil on a Legacy
/// scan, and before a scan starts.
var photoProcessing: PhotoProcessingStatus?
/// Photo processing sends a synthetic test capture in place of this scan's photos (DEBUG's
/// `-photoProcessingSyntheticCapture`), so its answer says nothing about the wall on screen.
var photoCaptureIsSynthetic = false

init() {}
}
Expand Down Expand Up @@ -1042,6 +1062,14 @@ protocol ScanActions: AnyObject {
func showAR()
func closeAR()
func startOver()
/// The homeowner's answer to sending this scan's photos for processing
/// (`PhotoProcessingStatus.Consent.asking`).
func answerPhotoConsent(_ yes: Bool)
/// A no after a yes: this scan's photos stop going to photo processing.
func stopSendingPhotos()
/// A photo-processing scan this build can't send, stopped before capture: choose Legacy and
/// start a new scan with it.
func scanWithLegacyInstead()
/// The app came back to the foreground on the camera-access failure: if access is now on,
/// the scan goes on without Start over. Does nothing otherwise.
func recheckCameraAccess()
Expand Down
Loading
Loading