Skip to content

ios: past-end requests keep their end; no requests past a wall end (#35, #38) - #47

Merged
AidenJohnston merged 5 commits into
t3/ios-mvffrom
t3/past-end-requests
Sep 26, 2026
Merged

AidenJohnston merged 5 commits into
t3/ios-mvffrom
t3/past-end-requests

Conversation

@AidenJohnston

@AidenJohnston AidenJohnston commented Sep 26, 2026 •

Copy link
Copy Markdown
Collaborator

Branches from t3/ios-mvf at 75dea41, which includes 3c7b83a ("end the wall where the phone is"). That commit changes where a walk end lands and refuses photos taken past an unexplored end. It doesn't touch the gap loop or the lag and see-behind tasks, so both issues still happen at its head.

#35: past-end requests

What was wrong

  • A server band request whose span reaches past a marked end never filled. The coverage map records nothing past an end (except ground past a limit end), but the request was still offered as a capture, so its bar stayed at 0 % and "I can't get there" was the only way out.
  • "Capture it now" on a past_end item clears that end. The gap screen has no way to mark the end again, so the request always ended with that side cleared.
    • Skipped: the end was lost. The next upload runs the wall out to whatever the fog saw.
    • Met: the next past_end request was planned from leftEnd ?? 0, which asks for the ground at the meter instead of the 2 m after the end.

Fix

  • GapPlanner.reachesPastEnd: a band request that reaches past a marked end gets no capture request, and it goes to review the same way isBeyondCapture does. Ground past a limit end is still capturable, since the map records it there. A span that ends within 0.01 ft of an end counts as reaching the end, not going past it. plan(for:leftEnd:rightEnd:limitEnds:) takes the limit ends, and the engine's three callers pass map.limitEnds.

  • ScanEngine.settleClearedEnd, run from afterGapResolved: if the past-end request ends without its end marked again:

    • skipped: the cleared end comes back with its kind and mark time.
    • met: the end moves to the far edge of the ground the request showed, still unexplored (GapPlanner.endAfterPastEnd).

    When the end was marked again (settlePastEnd), nothing changes.

Not in this PR: the gap screen still shows no "Wall ends here" and no end question during a past-end request. The engine already accepts both (markWallEnd, answerWallEnd), but the controls are UI work.

#38: walk guidance past a wall end

What was wrong: laggingBand and hiddenNearCamera look ±1 m around the camera and read cells that were seen before the end was set. Past an end, coveredFraction and markSkipped both ignore cells, so the task could never be met or skipped. This is what device run 2 hit at 2:41–3:38.

Fix: laggingBand, hiddenNearCamera and the see-behind check now count only cells between the ends (isWithinEnds). This is the same filter groundByMeterDone already uses.

Tests (HouseScanKit)

  • ServerGapTests.aBandRequestPastAMarkedEndIsNotACaptureRequest: wall, ground and facing requests past an end have no request, ground past a limit end still has one, and a span that ends at the end still has one.
  • ServerGapTests.aMetPastEndRequestMovesItsEndOn: the end moves 2 m on, and the next request asks for the following 2 m instead of the stretch at the meter.
  • GuidancePlannerTests.noCameraTaskPastAMarkedEnd: a lag past the right end no longer asks to tilt down (the walk goes left), and hidden cells past the ends no longer ask to see behind.
  • GroundDepthTests.groundPastALimitEndIsExportedAndSettlesARequest now passes limitEnds: [.right].

The app has no unit-test target, so the engine's end restore has no direct test. Its placement rule is endAfterPastEnd, which is covered above. The UI flow's sample answer lists a past_end item, but reading the autopilot, the band request before it is skipped on the synthetic replay, so the flow likely never reaches the past-end one. I haven't checked that on a run.

Also in this PR

  • aRequestSpanIsReadInTheServersFeet: this test planned a ground request 0.02 ft past an unexplored end to show the request isn't met. Past the end it now gets no request at all, so the test checks that and plans the shortfall case without the end.
  • The vendored scene.schema.json is refreshed to t3/server 074bf1d, which adds the battery object type (No way to mark an existing battery or other box on the wall #27). The server pushed that change after this branch's last CI run, so vendoredCopiesMatchServer now fails on every t3/ios-mvf run. If Sam refreshes it first, this commit can be dropped.

Fixes #35
Fixes #38

🤖 Generated with Claude Code

…go to review (#35)

- A server band request whose span reaches past a marked end has no capture request
  (GapPlanner.reachesPastEnd): the coverage map records nothing past an end, so its bar
  stayed at 0 % and "I can't get there" was the only way out. Ground past a limit end is
  still recorded, so a ground request there stays capturable. It goes to review, like a
  request beyond capture.
- A past_end request that ends without its end marked again no longer leaves that side
  without an end. Skipped, the end it cleared comes back with its kind and mark time. Met,
  the end moves on to the far edge of the ground the request showed, still unexplored
  (GapPlanner.endAfterPastEnd), so the next past_end request asks for the 2 m after it
  instead of the ground at the meter.
- ServerGapTests: aBandRequestPastAMarkedEndIsNotACaptureRequest,
  aMetPastEndRequestMovesItsEndOn.

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

@coderabbitai

coderabbitai Bot commented Sep 26, 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: b499d45f-4131-4ad5-a137-1094d516f3dc

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:M 30-99 effective changed lines. label Sep 26, 2026
Cells seen before an end was set stay in the coverage map, and the lagging-band and
see-behind tasks read them: after "Can't get there" put the right end 6 in from the meter
on device run 2, the walk kept asking to tilt up around 7 ft right and to tilt down at 5 ft
3 in right. Past an end nothing is observed (coveredFraction) or skipped (markSkipped), so
the task could never fill and "Can't get there" didn't clear it. laggingBand,
hiddenNearCamera and the see-behind check now count only cells between the ends.

GuidancePlannerTests.noCameraTaskPastAMarkedEnd.

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: 067f413363

ℹ️ 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 on lines +255 to +256
if let leftEnd, min(span.x, span.y) < feet(leftEnd) - tolerance { past.append(.left) }
if let rightEnd, max(span.x, span.y) > feet(rightEnd) + tolerance { past.append(.right) }

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 Treat an exact tolerance gap as past the end

When a server band span extends exactly 0.01 ft beyond a marked end, these strict comparisons still build a capture request. However, fraction(of:coveredBy:) and the ported server logic count gaps >= 0.01 ft as missing, so coverage clipped at the end can never satisfy that request and the homeowner must skip it manually. Use the same inclusive tolerance boundary here (and account for the exported end's rounding) that request settlement uses.

Useful? React with 👍 / 👎.

AidenJohnston and others added 2 commits September 26, 2026 17:25
…s past (#35)

aRequestSpanIsReadInTheServersFeet asked for ground 0.02 ft past an unexplored end to show
it isn't met. Past the end it now has no capture request, so the test checks that, and
reads the shortfall from a request planned without the end.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The server added the `battery` object type (issue #27) after this branch's last CI run,
and vendoredCopiesMatchServer fails on every t3/ios-mvf run until the copy is refreshed.
One enum value and its description; the app doesn't export batteries yet.

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

Copy link
Copy Markdown
Owner

Current PR #47 is CONFLICTING against t3/ios-mvf after #10 advanced to 6ee2874, which already refreshes the vendored scene schema to t3/server 074bf1d. Your PR description anticipated dropping the duplicate schema refresh if Sam did it first. Please reconcile with the current base through your branch’s normal workflow (no force push needed) and rerun the resulting head checks. I have not treated its #35/#38 fixes as landed in #10.

@SamGu-NRX

Copy link
Copy Markdown
Owner

Read-only review note for #47: beginServerGap says the cleared end stays cleared until the homeowner marks it again (ScanEngine.swift:1418-1420), but GapRequestScreen has no mark-end button or end-question controls. The PR body correctly lists that UI as not included; please make the code comment equally explicit. On a satisfied request without a mark, settleClearedEnd instead infers a new unexplored end from the ground request edge and setEnd records a new end mark time. Please confirm the packet should treat that inferred position/time as a homeowner wall-end mark, or keep inferred ends distinct from taps. This is a contract decision, not a claim that the current PR has already been tested on a phone.

…uests

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	ios/HouseScanKit/Tests/HouseScanKitTests/JSONSchemaValidatorTests.swift
@SamGu-NRX

Copy link
Copy Markdown
Owner

I checked the new 99e914c merge commit: #47 is mergeable and its iOS CI is running. The conflict resolution changed only the schema-test comment among #47-owned code, leaving "server’s files change and these are not / refreshed" awkwardly split across lines in JSONSchemaValidatorTests.swift. Please tidy that comment with the next substantive fix. The review gate remains open on the gap-screen re-mark claim and inferred end mark disposition from my earlier comment; I cannot post the no-open-findings line yet.

@AidenJohnston

Copy link
Copy Markdown
Collaborator Author

I merged the current t3/ios-mvf into this branch to clear the conflict. The only conflict was the line wrapping of a doc comment in JSONSchemaValidatorTests.swift; the base already has byte-identical vendored schemas from t3/server 074bf1d, so I took its copy, and this PR's diff no longer touches the schema files. I also checked that every GapPlanner.plan caller on the base still compiles with the new limitEnds parameter.

@SamGu-NRX

Copy link
Copy Markdown
Owner

Answering the caretaker's packet question, as the packet writer's owner. An inferred end must not become a homeowner mark. The spec (packet/README.md at d5439cf, "Marks, guidance and the scene") defines marks as "what the homeowner marked", and wall_end has no field for "the app put it here".

As written, settleClearedEnd's satisfied branch calls setEnd. That stamps markTimes[MarkKey.end(side)] with the current clock, so packetInputs writes a wall_end mark at the edge of the ground request, timed as if the homeowner had tapped it there.

Please:

  • keep a set of ends the app inferred;
  • leave those out of the packet's marks (ScanEngine+Packet.swift ~L119–L125), and clear their mark time;
  • let the guidance entry for the past-end request carry how it ended.

scene.json still carries the end, since the server needs it. The restore branch, which puts back the old end and its time, is right as it is.

"Can't get there" and "Wall ends here" during the walk are different: the homeowner stood there and tapped, so those stay marks.

@AidenJohnston
AidenJohnston merged commit d02cc11 into t3/ios-mvf Sep 26, 2026
3 checks passed
@SamGu-NRX

Copy link
Copy Markdown
Owner

@AidenJohnston Follow-up after merge at d02cc11: beginServerGap still says the cleared end stays cleared until the homeowner marks it again, but GapRequestScreen has no such control. More importantly, the satisfied branch of settleClearedEnd infers an end from a ground-request edge, calls setEnd, and stamps a new wall_end packet mark as though the homeowner tapped there. The packet owner confirmed inferred ends must not become homeowner marks. Keep the inferred end in scene.json, omit it from packet marks and clear its mark time, while preserving genuine tap marks and the restore branch. This contract finding was open when the green PR merged.

AidenJohnston added a commit that referenced this pull request Sep 26, 2026
Resolves the GapPlanner/ScanEngine conflicts with #47: the selector now
passes limitEnds, matches requests by view with a tolerance (same band and
need, reach within 0.1 m, 80% span overlap), and publishes how many views
it will actually raise as state.followUps. 'Show my result' shows only
when more than one view is left.

Co-authored-by: Cursor <cursoragent@cursor.com>
AidenJohnston added a commit that referenced this pull request Sep 27, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SamGu-NRX added a commit that referenced this pull request Sep 27, 2026
Brings in PRs #37, #41, #47, #48 and #51, 8604928 (result schema from
t3/server 9e42970) and d0ff1be (the walk asks for the wall to 4.5 ft).

Resolved:
- Server requests: S3's plan(for:leftEnd:rightEnd:limitEnds:) with the item
  first carried into the walk's s (walkRequest), in the three call sites.
- AR result: S3's in-scene result with occlusion (#41), drawn along the
  answer's wall (ResultPresentation.wall, else the walk's); publishWall
  redraws it after refreshing the result's wall. The auto-merge had put
  that redraw inside WallFrame's static geometry helper.
- JSONSchemaValidatorTests: S3's text; the hashes match the vendored files.
- Wall height: a 3D-map wall cell counts as covered once
  Map3DCoverage.wallHeight reaches wallWalkHeight, as S3's camera cells
  now do; the exported out_ft under map3d is still Map3DCoverage.wallHeight.

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

Labels

size:M 30-99 effective changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants