feat(3d): infer room placements and stop dead-ending on missing footprints - #795
Draft
smmariquit wants to merge 1 commit into
Draft
feat(3d): infer room placements and stop dead-ending on missing footprints#795smmariquit wants to merge 1 commit into
smmariquit wants to merge 1 commit into
Conversation
…rints Every class-hosting building now renders a 3D view, and rooms land where their code says instead of at a seeded random point. - src/lib/room-placement.ts: pure inference. Floor from the room code (first digit of a 3-4 digit number) or from directions prose, wing letter and odd/even side for the corridor x/y estimate, and null whenever the code carries no signal (CDC DECIMU, CHE 1, TCC-01, CAS B05 basements). Every result states its basis and its confidence in `reason`. - building-3d: `placeRooms` uses the inference, keeping the seeded-random fallback only for codes that say nothing; `approximateFootprint` draws a labelled stand-in box when OSM has no building. - overpass: report whether the chosen polygon actually contains the building's coordinates (cache version bumped), so the viewer can say the outline may belong to a neighbour instead of implying precision. - viewer: provisional banners with an OSM edit link, plus an editor-only "save suggested positions" list (per-room or bulk) that writes through the existing versioned room PATCH. - room_positions gains `source`; an inferred write never overwrites a manual one and never bumps the room version when it declines. Measured against prod (read-only): 38 of 41 class buildings resolve to an OSM footprint, 18 of those match a polygon that does not contain their coordinates, and the inference can place 304 of 638 class-hosting rooms (286 high confidence, 18 medium).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
smmariquit
marked this pull request as draft
July 26, 2026 11:13
Collaborator
Author
|
Opened non-draft by mistake, which auto-triggered the gated E2E stack; both E2E runs were cancelled within a minute and the PR is back to draft. The release on |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two goals: every class-hosting building should have a working 3D view, and rooms should land inside the model automatically instead of only by hand.
Part 1 — coverage
I replayed
fetchBuildingFootprint's exact selection rule (way["building"]within 35 m, prefer the polygon containing the point, else nearest centroid) against live OSM data for all 41 class-hosting buildings on prod. Read-only queries; nothing was written to any database.38 of 41 resolve to a footprint. 3 do not — these are the buildings to map in OSM:
A second, quieter failure mode showed up while measuring: 18 of the 38 "successful" buildings match a polygon that does not contain their own coordinates — the viewer was silently rendering a neighbour. DAAE Building → "UPLB CEM Alumni Gazebo", LHKCB Building → "Francisco O. Santos Hall", PTCF Building → "ICropS Tissue Culture Laboratory", Baker Hall Pool → "Charles Fuller Baker Memorial Hall", and so on. Full list: AFBED, Agricultural Systems Institute, Baker Hall Pool, CAS Annex 1, CDC, CEAT, CEM, DAAE, Forest Biological Sciences, Graduate School, IABE, ICropS, LHKCB, New Math, PHTRC, Physical Sciences, Temporary Common Classrooms, UPRHS.
Both cases now degrade honestly instead of dead-ending or bluffing:
OsmBuildingFootprint.containsPointcarries the signal; the localStorage cache version was bumped to 2 so stale entries cannot fake it.Part 2 — automatic room placement
src/lib/room-placement.ts— pure, no DB, no fetch.inferRoomSignal/inferBuildingPlacements/inferRoomPlacementreturn{ floor, posX, posY, confidence, reason }ornull.PS B-203→ 2,CEM 116→ 1), corroborated or overridden by directions prose ("2nd floor of Physical Sciences Building").confidencerates the floor only, andreasonalways states where it came from.CDC DECIMU,CEAT SHOP RM,CHE 1,ASLH 2,TCC-01all return null. Basement codes (CAS B05) return null too:room_positions.floorcannot express "below ground", and floor 1 would be a lie.Coverage on prod data: 304 of 638 class-hosting rooms can be placed — 286 high confidence, 18 medium, 0 low. The other 334 are named labs, lecture halls and shops with no numeric signal; they still appear in the model at the old seeded-random spot, which is now the fallback rather than the default.
Building3DVieweruses the inference for display, so the improvement shows up without anyone accepting anything.Editor assist, not an automatic prod mutation
In edit mode the sidebar lists every room the inference can place that has no saved position, each with floor, confidence and reason, and offers "Save all N" or per-room save. Saves go through the existing versioned
PATCH /api/admin/rooms/:id, so they get the same optimistic concurrency, editor history and sync-key refresh as a drag.This PR writes nothing to any database. No bulk INSERT was run anywhere; the maintainer decides what to apply, building by building, from the editor.
room_positions.sourcedrizzle/0042_room_position_source.sqladdssource varchar(16) NOT NULL DEFAULT 'manual'(0041 is taken by #794, so this is 0042). Existing rows baseline tomanual, protecting the 40 hand-placed positions.updateRoomPositionrefuses aninferredwrite over amanualrow, and returns without bumping the room version so a refused write does not pretend it happened. Registered inscripts/e2e-reset-db.ts; PGlite schema regenerated.Per AGENTS.md,
0042must be hand-applied to prod before the release that ships this. The admin position path selects the new column, so the migration has to land first.Verification
bun run test— 471 pass. 40 new unit tests over the real room codes above: floor extraction, the null cases, confidence degradation, pins staying inside the polygon, odd/even sides, determinism, and that skipped (human-placed) codes never appear in a suggestion.bunx vitest run— 43 files, 152 pass.bunx biome checkon every touched file — clean.bun run buildandbun run build:e2e— clean.EAA LH— a code with no digits — lands on floor 2 from its directions text.CI
Gated e2e is pending — no
run/e2elabel on purpose. An E2E run was already in flight onfeat/today-screenwhile I worked, and the shared Supabase pooler cannot take two. The new integration test (integration/services/admin.integration.test.ts, "an inferred room position never overwrites a manual one") has not run yet for the same reason.Deliberately left out
room_positions.flooris a positive int, so the ~10CAS B0xrooms return null instead of being pinned to the ground floor.RoomPlacementInput.buildingNameis threaded through so such rules have somewhere to land if one is ever needed.