# PropertyLab Research — local validation

Validated on 8 September 2026 in the isolated `codex/propertylab-research-advisor` worktree. This is an implementation and local integration record, not a production release certificate.

## Build and automated checks

| Check | Result |
|---|---|
| Vite client and SSR production builds | Passed using Node 22; existing portal dependency versions retained |
| PropertyLab PHP feature/unit tests | 46 passed, 250 assertions, isolated MySQL on port 33307 |
| PropertyLab Vue and JavaScript tests, including shared Mapbox loader recovery | 41 passed across 9 files |
| Python import fixtures | 3 passed |
| Migration constant guard | Passed: 176 references across 668 migrations |
| Whitespace validation | `git diff --check` passed |
| Public JavaScript credential check | No OpenAI project-key prefix found; supplied key stored encrypted in isolated backend only |

PHPUnit reports one existing configuration deprecation. The repository-wide suite-link guard reports an existing hardcoded suite link at `resources/js/Pages/Manage/AppointmentEngine/Dashboard.vue:117`; that same line exists at the base commit and this module does not change it. Its 71-link baseline is unchanged.

The three focused test groups total **90 passing tests**.

## Browser evidence

Authenticated Chrome testing used a disposable local preview account and the actual imported records. Browser tests explicitly blocked `/property/research/turns` while checking deterministic data and UI behavior.

- Map loads with Mapbox imagery and property overlays.
- Direct source evidence and a two-scheme comparison return HTTP 200. The checked source aggregates were BANDAR SETIA ALAM (RM900,000; reported PSF RM512) and BDR BUKIT RAJA (RM764,500; reported PSF RM471). These values are observations, not unit valuations.
- Price and PSF controls retrieve their respective metrics and trends; missing monthly values remain gaps.
- Moving near the first comparison bar marks that exact scheme as hovered on the map. The second selected scheme remains distinguishable. Camera coordinates, zoom, pitch and bearing do not change on hover.
- Light, Dark, Streets, Outdoors and Satellite Streets retain 70-degree pitch, terrain, building and property layers when switched in 3D.
- A new two-scheme comparison keeps the camera in a tilted 3D view instead of flattening it to zero pitch.
- Clearing property types empties both the regular property source and selected-marker source. The expanded legend opens and closes without another map control blocking it.
- The source drawer presents dates, 41 observations for the inspected comparison, source price/PSF/count fields and limitations. Technical provenance disclosures start collapsed.
- At 320px and 390px widths: no horizontal overflow or clipped toolbar buttons; the composer remains inside the viewport; unsent drafts survive Chat/Map/Evidence changes; Save and Undo have accessible names. Dialog focus stays inside the dialog, and Escape returns focus to the opening control.
- Browser verification reported no JavaScript runtime errors.

Destination coordinate validation, provisional/confirmed separation, duplicate handling, explicit preview without confirmation, stale-event rejection, cancellation races, scene/scenario independence, source number formatting and backend owner isolation are covered by the focused automated tests. Those tests do not establish live route-provider entitlements or live model quality.

## OpenAI and deployment status

The supplied OpenAI credential passed the existing provider authentication probe and was saved through the portal's encrypted credential repository. No key was added to committed configuration or browser assets.

The real OpenAI conversation test was blocked by automatic approval review because it would transfer selected property evidence to OpenAI. Explicit user approval has been requested for up to three bounded test questions. No real property-evidence conversation has been sent as part of this validation. Live answer quality, account quota, latency and provider failure behavior remain unverified until that step is approved and completed.

No production database, production credential store or running production portal was changed. The existing public explorer Site remains unchanged. Deployment and the broader release gates remain as described in [the module handbook](readMe.md).

## 9 September follow-up: KLCC and invalid planner recovery

The preview user's failed LRT question was recorded with `error_code=invalid_plan`, failed status and `is_charged=false`. A preceding user-submitted turn completed. Provider preparation was configured successfully. The testing approval request is not a runtime chatbot gate. Raw planner output was not retained, so the precise malformed field in that real request cannot be reconstructed.

The planner now explicitly identifies unsupported transit journey times and can repair one schema-invalid response within the existing round/time budgets. Rejected plans never execute. A second invalid plan returns a clearer interpretation failure without exposing model output. The supported alternative is station-proximity research; it cannot substantiate an LRT commute under 20 minutes. Transit routes, service schedules and waiting times remain unavailable.

Focused verification: 20 PHP feature/unit tests passed (163 assertions), including a mocked invalid LRT mode repaired into the specific transit limitation, repeated unknown-tool rejection without credits, and capability-label validation. These tests used a fake AI client; no new live OpenAI test was performed. The existing PHPUnit configuration deprecation remains.

The client/SSR build and four map-model tests passed. Authenticated browser verification of the KLCC home control reached longitude 101.712205, latitude 3.157376, zoom 16, pitch 70 and bearing -20 with Satellite Streets, terrain and building layers active and no JavaScript runtime errors. This coordinate is also the new-map default; existing conversations retain their saved camera until recentered. Browser verification blocked AI-turn requests. Artifacts: `browser-klcc-checks.json` and `advisor-klcc-default.png` in the local browser QA artifact directory.

## 9 September follow-up: answers and charts in the conversation

Moved the evidence panel into the left conversation. Streamed results render under their answer; saved answers can load their charts on demand. Direct map comparisons replace the welcome screen with a PropertyLab evidence response. The map fills the right pane. Compact navigation now has Chat and Map, and metric changes use the answer's property IDs instead of the current selection. Cards use the available pane width, and horizontal-bar labels wrap to fit.

Focused conversation, scene and chart tests: 19 passed, including direct-result placement and association with the correct answer. Authenticated browser checks confirmed one evidence panel inside the conversation, no welcome screen for an existing comparison, equal 906px map/conversation heights, linked bar hover with unchanged camera, and HTTP 200 for a PSF switch using all three original comparison IDs. At 390px and 320px there was no horizontal page overflow; switching Chat/Map preserved the typed draft. No browser runtime errors. Browser AI-turn requests were blocked. Artifacts: `browser-inline-checks.json`, `advisor-inline-desktop.png`, and `advisor-inline-mobile-{320,390}.png`.

## 9 September follow-up: Explorer and Advisor workflows

Introduced two primary tabs: Property Explorer (default) and AI Advisor. Explorer exposes search, independent type checkboxes, historical-price filtering, sorting, property cards, source price/PSF history and a comparison tray. The shared map is no longer implicitly narrowed to the latest answer. Marker inspection and comparison membership are separate actions; five-item comparison limits never prevent inspecting another property. Explicit card clicks focus the map; marker clicks do not request camera movement.

Focused tests: 19 passed across the scene, conversation and explorer components. The regression test fills five comparison slots, inspects a sixth and seventh property and verifies comparison membership and camera state remain unchanged. Explorer tests distinguish viewing from comparison and verify independent type selection and search events.

Authenticated browser checks selected six distinct properties by real map clicks, three after filling the comparison. All 18,917 map features remained available. No ease/fly/fit camera commands were issued by those clicks (Mapbox terrain settling changed the sampled camera slightly). Typing KLCC returned four cards; unchecking their shared category removed those results. Switching into AI Advisor and back retained the draft. Both 320px and 390px layouts had no horizontal overflow. No browser runtime errors. AI-turn requests were blocked throughout. Artifacts: `browser-modes-checks.json`, `explorer-desktop.png`, `advisor-mode-desktop.png`, `explorer-mobile-320.png`, and `explorer-mobile-390.png`.

Explorer detail checks returned HTTP 200 for both price history and PSF, kept the Explorer tab active with the evidence visible, retained 18,917 map features, and returned successfully to the property cards. The disposable comparison created by that test was deleted successfully. Result: no browser runtime errors (`browser-explorer-details.json`). On compact screens Explorer uses one scrollable surface so expanded filters cannot make lower controls inaccessible.


## 9 September follow-up: compact filters, fresh chats and Map settings

The Explorer header now contains search and a Filters popup with staged type/price changes, Apply, draft Reset, close/Escape cancellation and focus return. Its general research toolbar is hidden. Advisor has New chat and a searchable History drawer. Entry from Explorer creates a fresh local chat without an empty database row; previously sent conversations remain available through History. Explorer sessions restore independently. This explicitly supersedes the previous primary-tab draft-retention behavior recorded above; compact Chat/Map subview retention is unchanged. The unified, initially collapsed Map settings panel includes colored property-type filtering alongside appearance, rail and amenities.

Validation: client and SSR builds passed. Twenty focused JavaScript tests passed, including staged filter apply/cancel behavior, conversation evidence and independent map inspection. All 17 isolated Advisor feature tests passed (154 assertions), including owner-isolated history, first-question titles and exclusion of evidence-only workspaces. PHPUnit reported one existing configuration deprecation. No migrations or live model calls were needed.

Authenticated browser checks passed for hidden Explorer toolbar, initially collapsed Map settings, two-way type-filter synchronization, actual filtered map source data, Escape focus return, discarded draft filter changes, Explorer search/type/price restoration, blank Advisor entry, history loading a saved conversation and New chat clearing it. At 390px the filter dialog fits the viewport with Apply visible and no horizontal overflow. No JavaScript runtime errors. AI-turn endpoints were blocked. Artifacts: `browser-history-filters.json`, `explorer-filters-compact.png`, `advisor-chat-history.png`, and `explorer-filters-mobile.png` under `/home/ubuntu/propertylab-browser-qa/artifacts/`.

## 9 September follow-up: smaller markers, Heat map tab and one masthead

Reduced ordinary marker radius from 8px to 5px at zoom 15, with smaller clusters, selected points and hover rings. The existing 8px feature-query tolerance remains unchanged. Added Heat map between Explorer and Advisor using fixed GeoJSON cells with recorded PSF, recorded price and mapped-scheme concentration. Price cells use a median of at least three valid scheme values; sparse occupied cells are grey. State/type cohorts, approximate cell sizes, fixed numeric colour bands, opacity, optional overhead view, source interpretation and keyboard-accessible cell/property lists are included. A selected cell opens its details at the top of the sidebar. Map clicks and property-list links connect back to Explorer. No new backend endpoints, database migrations or model calls are involved.

The Research page opts into an integrated shell header: its own masthead contains portal-menu access, while the duplicate shell heading/bar is omitted. The shell's default behavior for other pages is unchanged. Menu closure also has an accessible name.

Thirty-two focused JavaScript tests passed across heat-map aggregation, cell-detail interaction, map models, Explorer, conversation evidence and scene state. The browser exposed a Map icon/import collision that prevented cell details opening; the icon was aliased and a regression test now checks cell selection and Explorer navigation. The final client and SSR builds passed, with existing bundle-size and unrelated unused-import warnings.

Authenticated browser checks passed for tab order, smaller paint radii, 10,121 default occupied heat cells, hidden ordinary markers in Heat map, heat-layer restoration after a style change, actual map-cell clicking, exact cell values/contributors, concentration counts, 1 km price-cell IDs, empty type selection, keyboard cell selection, opening the associated Explorer card, and fresh Advisor entry after Heat map. At 390px, controls and portal-menu navigation work with no horizontal overflow. No JavaScript page or console errors were reported by the final heat-map browser run. Its initial mobile header assertion counted hidden conversation headers; the visible-header check is recorded separately. AI-turn endpoints were blocked.

Artifacts in `/home/ubuntu/propertylab-browser-qa/artifacts/`: `browser-heatmap.json`, `heatmap-psf-desktop.png`, `heatmap-cell-details.png`, `heatmap-mobile-controls.png`, `heatmap-mobile-map.png`. Supplementary visible-header and reduced-marker hit checks: `browser-heatmap-header-markers.json` and `explorer-smaller-markers.png`. Mapbox fill-layer API reference used during implementation: https://docs.mapbox.com/style-spec/reference/layers/#fill .

Supplementary browser verification passed: exactly one visible masthead at 390px, portal menu opens/closes, and two distinct smaller map markers can still be clicked to select their Explorer cards. The marker check uses actual rendered pixel hits because projected ground coordinates can differ from the visible circles in a tilted terrain view. No runtime errors were reported.

## 9 September palette adjustment

Changed the shared heat palette to the user's requested blue → light blue → yellow → orange → red scale. Both legends, map fills and cell-list swatches consume the same palette; insufficient price evidence remains grey. Metric thresholds and calculations are unchanged. Client/SSR build passed. Authenticated browser verification confirmed all five legend colours and matching map feature colours, with no page errors. Inspected `heatmap-blue-yellow-red.png`; machine checks are in `browser-heatmap-colours.json` in the browser QA artifact directory.

## 9 September detailed PSF ranges and numeric map legend

Expanded PSF to six labelled bands: <300, 300–<600, 600–<1,000, 1,000–<1,500, 1,500–2,000 and >2,000 RM/sq ft. Exactly 2,000 remains in the penultimate band. Added a metric-specific palette so the existing five-band price and concentration scales retain their colours. Sidebar swatches, map fills and cell lists use the same palette; the map-overlay legend now labels every colour with its numeric range and unit rather than only labelling the endpoints. Grey continues to identify insufficient price evidence.

Nine focused tests passed, including exact 1,000/1,500/2,000 boundaries, map-feature colour assignment and numeric labels in both legends. Client and SSR builds passed. Authenticated browser checks confirmed all real map cells match their PSF band, all six ranges appear in both legends, price/count switch to five correct ranges, and the 320px legend fits without horizontal overflow. No page or console errors. Artifacts: `browser-psf-ranges.json`, `heatmap-psf-ranges-desktop.png`, `heatmap-psf-ranges-mobile.png` in the browser QA directory. AI requests remained blocked.

## 9 September available values, limited coverage and green-to-red palette

Price/PSF cells now show the median whenever at least one positive finite scheme value exists. One or two valid observations are labelled Limited coverage in cell details, the cell list and map hover. Grey is reserved for zero valid price values and is labelled No valid price data. The selected-cell count now uses correct singular/plural wording. The source note distinguishes an individual observation from an area benchmark.

Applied the requested six-step light green → green → yellow → orange → red → dark red palette across PSF, price and concentration. PSF retains its six numeric ranges, including the strictly greater-than-2,000 upper band. Price and concentration split their prior open upper bands at RM 2 million and 41 schemes so all six colours have corresponding labelled numeric ranges.

Twelve focused tests passed, including one/two/three-observation coverage, invalid/missing-value exclusion, zero-value grey cells, exact upper PSF boundaries and a rendered single-property detail. Client/SSR build passed. Authenticated browser verification of RESIDENSI TRX 1, TUN RAZAK EXCHANGE at cell centre 3.1418, 101.7180 confirmed RM 2,440/sq ft, one valid property, a Limited coverage label and dark-red fill. All 8,170 limited-coverage cells in the current PSF map had actual positive values. The map and legend expose the same six colours; price/count both have six labelled bands. Mobile had no horizontal overflow and no page/console errors occurred. AI requests stayed blocked. Inspected the TRX detail screenshot.

Artifacts: `browser-coverage-green.json`, `heatmap-trx-limited-coverage.png`, and `heatmap-green-red-mobile.png` in `/home/ubuntu/propertylab-browser-qa/artifacts/`.


## 9 September 2026 — eight PSF bands and Amaya source check

PSF thresholds changed to 400, 500, 700, 800, 1,000, 1,500, and 2,000 (final upper band strictly greater than 2,000). Eight colours progress light green, green, yellow-green, yellow, amber, orange, red, dark red. Both legends and cell fills use the same metric configuration. Price and concentration retain their six bands.

Validation: 12 focused Vitest tests passed; client and SSR build completed. Authenticated browser QA confirmed eight labelled colours, real TRX RM2,440 dark-red limited-coverage cell, other metrics retaining six bands, and mobile legend fit without horizontal overflow. First browser attempt overlapped the build and encountered HTTP 409; post-build retry passed with no page or console errors. Screenshots and browser-eight-psf.json are in /home/ubuntu/propertylab-browser-qa/artifacts/.

Read-only Amaya Maluri audit: all 21 imported monthly rows match the original monthly summary dataset on month, PSF, median price, and count. Available span August 2021–October 2024. The default April 2024–March 2026 window contains four observations and 20 missing months. The chart aligns to the snapshot-wide end month, rather than the latest month for each property. Source gaps are not proof of zero transactions. Evidence: /home/ubuntu/propertylab-browser-qa/artifacts/amaya-monthly-audit.json. No values imputed or database writes performed.


## 9 September 2026 — full available property history

Fixed default get_scheme_evidence date selection: when neither date is supplied, use the selected schemes’ first and last available monthly records instead of the snapshot-wide latest 24 months. Explicit dates remain authoritative. Comparison histories share the selected schemes’ combined available span. Added a chart subtitle with displayed date range, non-null value count, and explanation of gaps using the existing subtitle UI. No client rebuild or database migration required.

Validation: ResearchRepositoryIntegrationTest and ResearchCalculationsTest passed, 15 tests / 68 assertions (existing PHPUnit configuration deprecation). Regression covers an older observation outside the former default, internal gaps, explicit dates, independent missing PSF, and no-history property. Authenticated browser QA on Amaya Maluri verified Price and PSF each contain 21 observed values across 39 calendar months, August 2021–October 2024. The visible graph and accessible table were inspected; 18 internal gaps remain unfilled. No browser page errors or AI calls. Artifacts: /home/ubuntu/propertylab-browser-qa/artifacts/browser-amaya-full-history.json and amaya-full-history.png. Existing saved results retain their original requested period; reopen property history to generate the updated default result.


## 9 September 2026 — Explorer cards, details, sorting and area search

Card body/title and map selection now open a sliding right-hand evidence panel with immediate active-card styling. The desktop list remains interactive; mobile details fit the workspace width with close/Escape, focus return and keyboard containment. Save/compare controls do not trigger card inspection. Price and PSF support ascending and descending order, with missing/invalid values last. Search resolves exact scheme names or recorded administrative fields, otherwise offers nearby source-backed geographic choices and includes properties within an explicitly approximate 3 km area. Mapbox Popup anchors information below the selected/hovered marker.

Details operations serialize conversation revisions, ignore superseded responses for presentation, and retain revision updates for the next request. Save retries preserve their evidence-call context, preventing a pending autosave from waiting on its own details operation.

Validation: 10 focused Vitest tests across explorerModel, ExplorerPanel and ExplorerUX passed. Client and SSR builds passed. Authenticated 1920px/390px browser pass confirmed Sunway mapped area with 70 filtered properties and alternative locations; all four monetary sort orders; Bandar Sunway PJS 7/15 card body opens details and blue border; popup approximately 14px below the projected marker; delayed first request followed by another card leaves the second property selected; mobile panel covers x=0 to390 without overflow, focuses Close, and returns to the list. No browser page/console errors or AI requests. Evidence: /home/ubuntu/propertylab-browser-qa/artifacts/browser-explorer-right-details.json, explorer-right-details.png, explorer-mobile-details.png.


## 9 September 2026 — monthly observations and moving average

Monthly Price and PSF charts now format axis ticks, tooltips and table dates as MMM-YYYY. Recorded values are dots without connecting lines. A separate dashed trailing six-calendar-month average requires a full six-month window and at least three positive observed monthly values. Missing months are excluded, never zero-filled; insufficient windows remain gaps. The table includes the derived average, tooltips identify its observation count, and property identity remains linked to the map. Comparison legends toggle both datasets for each property.

Validation: 10 focused Vitest tests passed across chartModel and EvidenceChart, covering month formatting, calendar windows, missingness, no future/stale carry, downward trends, exact Union Suites calculations and rendered chart configuration. Client and SSR builds passed. Authenticated desktop/mobile browser QA verified Union Suites dates and average values, the PSF table and chart, no mobile horizontal overflow and no page/console errors. AI requests remained blocked. Its first eligible average is RM1,070/sq ft in Jun-2022 and last is RM1,136.25/sq ft in Jul-2024 (+6.19%); the final value is below its Sep-2023 average of RM1,341.50/sq ft, so recent decline is preserved. Screenshots were visually inspected.

Artifacts: /home/ubuntu/propertylab-browser-qa/artifacts/browser-moving-average.json, union-suites-moving-average.png and union-suites-moving-average-mobile.png. Build log: /tmp/propertylab-moving-average-build.log.


## 9 September 2026 — cumulative average across displayed history

Replaced the six-month rolling window with a cumulative average from the beginning of the displayed period through each date. The first valid observation starts the line; all positive recorded monthly values have equal weight. Missing months retain the prior calculated average without becoming source observations. No future observations are included. Chart.js stepped mode before holds the old value until the next observation date (verified against the installed line renderer). Dots, MMM-YYYY labels, linked property identities and separate table column are retained. Legend and tooltips now explicitly label Cumulative average.

Ten focused chartModel/EvidenceChart tests pass, including sparse SS 16, SUBANG JAYA history, missing/invalid values, chronological evaluation of unsorted input, falling values, date formatting and chart configuration. SS 16's six supplied monthly prices total RM6,632,000, yielding a final cumulative average of RM1,105,333.33; no six-month coverage threshold applies.

Client/SSR build passed; the final client rebuild includes the verified step direction. Authenticated browser QA selected SS 16, SUBANG JAYA (Serviced Apartment, scheme 6b4d6057a194bb91) using its Search location choice, and verified averages across all 51 displayed months, first RM923,000 and last RM1,105,333. Desktop screenshot inspected: source dots stay unconnected, the dashed cumulative average spans May-2021–Jul-2025 and changes only at recorded months. Mobile has no horizontal overflow. No page/console errors; AI requests blocked. Artifacts: /home/ubuntu/propertylab-browser-qa/artifacts/browser-cumulative-average.json, ss16-cumulative-average.png, ss16-cumulative-average-mobile.png. Build logs: /tmp/propertylab-cumulative-average-build.log and /tmp/propertylab-cumulative-average-client-final.log.


## 9 September 2026 — overall descriptive trend

Replaced the cumulative-average staircase with a straight least-squares trend fitted to each property's observed monthly values against elapsed calendar months. The line is labelled Overall trend / Trend estimate, requires three valid dated observations and stays within the observed span. Missing source values remain unconnected gaps, not zeroes; the derived line is explicitly a period summary, not a forecast. Limited-observations copy appears below eight records. This answers the user's intended direction question without cumulative weighting muting later price movement. Uses the existing Chart.js implementation and property colours; no new chart runtime or data mutation.

Ten focused chart model/component tests passed: actual calendar spacing, raw gap preservation, no extrapolation, sparse multi-year fit, invalid values, increasing/decreasing/flat fits, dates and chart configuration. Read-only isolated-database check of all available history confirmed SS 16 Serviced Apartment has six PSF observations, fitted endpoints 1151.92–1162.24 RM/sq ft (essentially flat); Highpark has 38 observations, fitted endpoints 1190.41–1300.06 RM/sq ft (+9.21%). These are fitted changes, not repeat-sales returns. Source audit: /tmp/propertylab-trend-source.json.

Client and SSR build passed. Authenticated browser QA verified both real PSF charts and matching fitted table endpoints, Highpark's upward line and SS 16's nearly flat line, limited-observations copy only for the sparse example, and mobile fit without horizontal overflow. Desktop and mobile screenshots visually inspected: recorded dots are unconnected, trend is straight without staircase, MMM-YYYY ticks fit. No page or console errors; AI requests blocked. Artifacts: /home/ubuntu/propertylab-browser-qa/artifacts/browser-overall-trend.json, highpark-overall-trend.png, ss16-overall-trend.png, highpark-overall-trend-mobile.png. Build log: /tmp/propertylab-overall-trend-build.log.


## 9 September 2026 — first/latest three retained months and candidate exclusions

User selected three recorded months, skipping missing months with actual dates shown. Added median comparison of the first and latest three retained observations, requiring six retained months to avoid overlap. Candidate exclusions are applied before endpoint selection; both adjusted and unfiltered results expose their own date ranges. No annualisation or appreciation guarantee is presented.

Outlier screening uses a Theil–Sen residual baseline, median absolute residual deviation, and absolute modified score >3.5. Seven observed months minimum, positive residual MAD required, and no automatic exclusion if over 25% would be flagged. These are exploratory product safeguards, not statistical confidence guarantees. Reference for modified scores and potential-outlier interpretation: https://www.itl.nist.gov/div898/handbook/eda/section3/eda35h.htm. A trend-based baseline avoids treating gradual appreciation as an outlier merely because prices changed over time. No database mutations. Excluded values stay in the table; Show excluded reveals hollow dots, while the fitted line and comparison retain their exclusions.

16 focused Vitest tests pass across historyAnalysis, chartModel and EvidenceChart. Tests cover Greenfield's six candidates (May-2021 1349, Sep-2021 1034, Dec-2021 747, Feb-2022 693, Dec-2023 1062, Jan-2025 1146 PSF), Highpark's four candidates with legitimate later highs preserved, seven-observation screening, sparse/zero-spread fallback, source immutability, missing months and dates, group medians and the reveal control. Read-only source checks: Greenfield first retained Apr-2021/Aug-2021/Mar-2022 median935; latest Oct-2024/May-2025/Jan-2026 median968, +3.5294%, versus unfiltered +1.782%. Highpark first retained median1159 and latest1415, +22.088%. Source evidence is /tmp/propertylab-greenfield-source.json and /tmp/propertylab-trend-source.json.

Client and SSR builds passed. Authenticated browser QA in an explicitly created isolated conversation verified Greenfield and Highpark summary values/date ranges, all six/four exclusion labels, hidden-by-default controls, revealed hollow dots, unchanged adjusted results and mobile fit without horizontal overflow. Screenshots visually inspected. The first browser attempt reused an actively updated conversation and received 409 revision conflicts; the isolated-session rerun passed with no page/console errors. No AI requests. Greenfield endpoint-group medians increase3.5% while the retained-history line declines slightly; the two are separately labelled statistics, not interchangeable claims.

Artifacts: /home/ubuntu/propertylab-browser-qa/artifacts/browser-outlier-analysis.json, greenfield-outlier-analysis.png, greenfield-outliers-revealed.png, highpark-outlier-analysis.png, highpark-outliers-revealed.png, highpark-outlier-analysis-mobile.png. Build log: /tmp/propertylab-outlier-analysis-build.log.


## 9 September 2026 — Explorer list follows map automatically

Removed the opt-in map-area checkbox and all search paths that disabled viewport filtering. The Explorer now derives card identities from rendered property dots and every leaf of rendered clusters, while retaining shared type/price filters. Manual map gestures and the KLCC reset release a prior text/area search. Programmatic search focus retains the query. Property list pagination/scroll reset when the visible identity set changes. AI Advisor browsing scope remains separate.

Map source/style changes invalidate pending cluster callbacks. Refresh after move-end, throttled rendered frames and idle; compare identity signatures before emitting. Throttled frame refresh avoids waiting for background imagery to become idle after a source update. Bounds remain a fallback until the map reports its first identity set.

10 focused tests passed across mapVisibility, ExplorerUX and ExplorerPanel, covering deduplicated dots/cluster leaves, empty views and stale-source errors, automatic card filtering, manual browse releasing prior search, card/detail selection races, and existing filter controls. Initial browser QA identified search marker/list delay when only waiting for idle; the rendered-frame refresh addresses this.

Final client/SSR build passed. Authenticated browser pass confirmed 295 initial visible identities, one exact-search property, 200 after a real mouse drag with search cleared, 174 after excluding Serviced Apartment, and 2,585 identities represented by visible clusters at zoom11. At each checkpoint the displayed total equalled the rendered-marker/cluster-leaf identity set and every rendered card belonged to it. Mobile had no horizontal overflow; no page/console errors or AI requests. Screenshot inspected; the count continues to track viewport changes after the checkpoint. Evidence: /home/ubuntu/propertylab-browser-qa/artifacts/browser-map-follow.json and explorer-map-follow.png. Build log: /tmp/propertylab-map-follow-final-build.log.
