GIS-iPad

App Store Manual Acceptance Test Plan

Use this plan before submitting Meridian to TestFlight, the iOS App Store, or the Mac App Store. It complements docs/release-candidate-checklist.md by walking through a realistic planner/engineer review instead of isolated smoke checks.

The main scenario is a Hamilton school access review: import schools, roads, and parcels; run a 30 m buffer around schools; identify affected parcels and nearby roads; edit a proposed field note; export data and a map; then confirm the same project behaves correctly on iPad, Mac, and the scoped iPhone companion.

It then walks every major feature surface in depth so a release candidate is exercised end to end, not just the headline flow:

It also covers two newer surfaces: the on-device natural-language Command panel (iPad) and the iPhone companion (view / layer visibility / single-feature attribute edit / notes / iCloud save).

Release Gate

Do not submit the build if any of these fail:

Classify failures as:

Evidence Record

Create an evidence folder outside source control for each candidate build, for example:

mkdir -p ~/Desktop/Meridian-Release-Evidence/<build>/manual-acceptance

Record:

Field Value
Build/version  
Git SHA  
iPad model and iPadOS  
Apple Pencil model  
iPhone model and iOS  
Mac model and macOS  
iCloud container available on device Yes / No (Open-from-Files fallback)
Network state tested Online / offline / both
Tester  
Date  
Result PASS / FAIL / PARTIAL
Blocking issues  

Capture screenshots or short screen recordings for the 30 m buffer, selected parcels, a categorized/graduated symbology legend, styled labels, a definition filter, a field-calculator result, an edited/drawn feature, markup notes, the export inspector, each export format, the PDF/map layout, and the Mac parity run.

Test Data

Use the manual QA fixture pack in Resources/TestData/real-hamilton/. These files are already in the repo and are small enough to move through Files, iCloud Drive, AirDrop, or a connected Mac.

File Expected contents Use
Resources/TestData/real-hamilton/hamilton_schools.geojson 7 Point features. Fields: name, school_type. Bbox about lon 175.280395...175.3014103, lat -37.7921959...-37.7841864. School labels, 30 m Buffer, point density, reachability starts.
Resources/TestData/real-hamilton/hamilton_roads.geojson 203 line features. Fields include name, road_class, speed_kph, lanes, length_m, travel_time, oneway. Network Reachability, Line Density, snapping, road styling.
Resources/TestData/real-hamilton/hamilton_parcels.geojson 2,193 polygon features. Fields include parcel_id, land_use, area_sqm, name. Select by Location, Summarize Within, attribute table scale, parcel export.

Source note: Resources/TestData/real-hamilton/README.txt identifies the fixture source as OpenStreetMap contributors under ODbL 1.0, fetched 2026-06-12 for screenshot and QA seeding.

Before a run, verify the files are present:

jq '.features | length' Resources/TestData/real-hamilton/hamilton_schools.geojson
jq '.features | length' Resources/TestData/real-hamilton/hamilton_roads.geojson
jq '.features | length' Resources/TestData/real-hamilton/hamilton_parcels.geojson

Expected output:

7
203
2193

For iPad testing, make the three .geojson files visible in the Files app before starting. For Mac testing, import the files directly from the repo path above. The separate GISPad/Resources/SampleData/ Hamilton files are smaller app-test fixtures used by Rust tests; use Resources/TestData/real-hamilton/ for this manual App Store walk-through.

Preflight Build Checks

Run the automated baseline before the manual pass where possible:

cargo test --manifest-path crates/gis_core/Cargo.toml --lib
xcodebuild test -project Meridian.xcodeproj -scheme Meridian -destination 'platform=iOS Simulator,name=iPad Pro 13-inch (M4)' -only-testing:MeridianTests
# Companion routes to the phone UI tree only on the phone idiom — also build/run on an iPhone simulator:
xcodebuild test -project Meridian.xcodeproj -scheme Meridian -destination 'platform=iOS Simulator,name=iPhone 17' -only-testing:MeridianTests
xcodebuild test -project MeridianMac.xcodeproj -scheme MeridianMac -destination 'platform=macOS' -only-testing:MeridianMacTests
Scripts/check-platform-parity.sh

The relevant automated suites for the new surfaces are CommandPlannerTests (natural-language planner), WorkspacePhase4Tests (Command wiring/prefill), and the phone companion tests (PhoneProjectLibraryModelTests, PhoneWorkspaceModelTests, ProjectDocumentCoordinatorTests, plus the iPhone-idiom UI tests). Confirm these are green before the manual pass.

Expected result: tests pass or each failure is already documented as unrelated simulator/device flakiness with a physical-device retest plan.

iPad Scenario: Hamilton School Access Review

Run this on a physical iPad using the closest-to-release build available. Repeat the final pass with a Release/TestFlight build.

This scenario is grouped by feature area. The core lifecycle (project, import, table, save) runs first, then each feature surface is exercised in depth. Unless a step says otherwise, keep all three Hamilton layers loaded.

Project Lifecycle And Core Import

ID Step Expected result
IP-01 Launch Meridian with Wi-Fi off or no-basemap selected. Project Gallery appears quickly. No account, cloud prompt, or blocking network error appears.
IP-02 Create a project named Hamilton School Access Review. The project opens to the map workspace with empty state, layer controls, and bottom tool dock visible.
IP-03 Import hamilton_parcels.geojson. Name layer Hamilton Parcels. Import completes without blocking warnings. Layer count is 2,193 polygons. Map zooms to central Hamilton.
IP-04 Import hamilton_roads.geojson. Name layer Hamilton Roads. Import completes. Layer count is 203 lines. Roads draw above parcels.
IP-05 Import hamilton_schools.geojson. Name layer Hamilton Schools. Import completes. Layer count is 7 points. Points appear inside the parcel/road extent.
IP-06 Reorder layers: schools above roads above parcels. Set parcels to low opacity, roads medium contrast, schools accent color. Layer list order matches the map. Opacity/style changes render immediately and persist after closing/reopening Layer Details.
IP-07 Turn labels on for Hamilton Schools using the name field. School names appear at sensible zoom levels. Labels stay readable while panning and do not crash during refresh.
IP-08 Open the schools attribute table. Search for Peachgrove. One school row is found: Peachgrove Intermediate School. Selecting the row highlights the correct map point.
IP-09 Open the parcels table. Sort by area_sqm, then search residential. Table remains responsive and virtualized. Search/sort controls do not freeze the map.
IP-10 Save and close the project, then reopen it. All three layers, counts, order, styles, labels, and camera position survive reopen.

Importing Data: All Supported Formats

Meridian imports GeoJSON, GeoPackage (.gpkg), Shapefile (.shp/zipped), read-only Esri File Geodatabase (.gdb), KML/KMZ, CSV/delimited text, the built-in Open Data Library, and connected services (OGC API Features, WFS, ArcGIS Feature Service). Use any small known-good files you have for the non-GeoJSON formats; if a format’s file is unavailable, mark its row N/A — no fixture rather than passing it untested. Do this work in a scratch project so the Hamilton review project stays clean.

ID Step Expected result
IMP-01 Open Import Data and review the format list. GeoJSON, GeoPackage, Shapefile, Geodatabase, KML/KMZ, CSV/delimited, and the Open Data Library are all offered with readable descriptions.
IMP-02 Import a GeoPackage (.gpkg) with at least two layers. The multi-layer picker lists each table; selected layers import with correct geometry types and counts. Unsupported-CRS layers are reprojected to WGS84 or warned, never silently mangled.
IMP-03 Import a Shapefile (zipped .shp/.dbf/.prj). Features import with attributes; the .prj CRS is honored (reprojected to WGS84) or warned.
IMP-04 Import a read-only File Geodatabase (.gdb). Feature classes are listed and import read-only with correct geometry/counts. No write/edit-back is offered for .gdb.
IMP-05 Import a KML and a KMZ file. Folders/placemarks import; KMZ bundled icons do not break import. Geometry lands in the correct location.
IMP-06 Import a CSV with coordinate columns. The CSV flow lets you map coordinate columns; points land in the correct location; non-coordinate columns become attributes.
IMP-07 Open the Open Data Library and add a small Natural Earth dataset. The dataset downloads (online) and adds as a normal layer with public-domain attribution recorded.
IMP-08 Add a connected source (OGC API Features, WFS, or ArcGIS Feature Service) if one is reachable. The service connects, lists layers, and streams features. Any credentials are stored in the keychain only — confirm later they are never written into a .gispad export (see EXP-09).
IMP-09 Import a deliberately malformed file (truncated JSON or wrong geometry). Import fails with a calm, specific error and changes nothing. The app does not crash or half-import.

Symbology And Styling

Open Symbology for a layer. It has three tabs — Symbol, Color, Size — and the Color tab exposes the modes Single, Categories, Graduated, and (when the layer supports them) Heatmap and Extrusion.

ID Step Expected result
SYM-01 On Hamilton Roads, in Symbol, set a line color, Stroke width, Opacity, and try Line Style = Solid/Dashed/Dotted. Toggle Direction Arrows. Each control renders immediately on the map. Dashed/Dotted and direction chevrons appear correctly along the lines.
SYM-02 On Hamilton Parcels, in Symbol, set Fill, Outline, Opacity, and try Fill Pattern = Solid/Hatch/Cross/Dots. Polygon fill/outline and the chosen pattern render correctly and persist.
SYM-03 On Hamilton Schools, in Symbol, adjust Point marker size, then change the Marker shape (circle, square, diamond, triangle, pentagon, hexagon, star, cross, pin, …) and toggle fill/outline. Point markers resize live; the chosen shape renders immediately and applies to single, categorized, and graduated symbols. Hollow (outline-only / fill-only) variants render correctly.
SYM-04 Color tab → Categories on Hamilton Parcels using land_use. Pick a palette, then Load More if categories are truncated. Distinct colors per land-use value; a palette swatch row is shown; “Other values” and a No-Data symbol appear when applicable. Map matches the legend.
SYM-05 Color tab → Graduated on Hamilton Parcels using area_sqm. Try classification methods Equal Interval, Quantile, Natural Breaks, Std. Dev., change class count, and pick a Color Ramp with Reverse. Class breaks and colors update for each method; reversing flips the ramp; the map reflects the classes. No crash on re-classification.
SYM-06 Size tab → enable Graduated Size on Hamilton Roads using a numeric field (e.g. speed_kph or lanes); set Min/Max and a classification. Line width varies by class with a correct legend preview.
SYM-07 Size tab → enable Graduated Opacity on Hamilton Parcels using area_sqm; set Min/Max. Feature opacity fades across the value range with a legend preview.
SYM-08 Color tab → Heatmap on Hamilton Schools (points). Adjust Radius, Intensity, Opacity, color ramp, optional weight field. A heatmap renders from the 7 points (sparse is fine). Controls update live. (If Heatmap is not offered for this layer, record N/A.)
SYM-09 Color tab → Extrusion on a polygon layer that supports it (constant/field/graduated height). 3D extrusion renders with the chosen height mode/scale/base. If Extrusion is not offered (no height field), record N/A — do not force it.
SYM-10 Select one or more features and use Override Selected Feature(s) to set a custom symbol; then Remove Override / Clear All. Overrides apply only to the chosen features; the “X of 60 overrides used” counter is accurate; remove/clear restores layer symbology.
SYM-11 Save current style as a named preset, change the style, then Apply the saved preset; delete a preset. Preset saves, re-applies exactly, and deletes.
SYM-12 Use symbology Undo/Redo, then Apply; reopen Symbology. Undo/redo step correctly; disabled when nothing to undo/redo. Applied style persists; Cancel discards unapplied edits; Reset restores defaults.
SYM-13 Close and reopen the project. All symbology — mode, fields, classification, ramps, graduated size/opacity, marker shape, overrides, presets — survives reopen.

Labelling

Open Labels for a layer.

ID Step Expected result
LBL-01 Enable labels on Hamilton Roads with Field = name. Set Font (Sans/Bold), Placement, Size, Text color, and Halo (Off/Soft/Strong) with a halo color. The Preview and the map reflect each change. Labels stay legible against the basemap.
LBL-02 Enable the label Background; set fill, stroke, opacity, stroke width, corner radius, and padding. Label backgrounds render with the chosen styling and do not clip text.
LBL-03 Set a Zoom Range (min/max) so labels only show within a band. Labels appear/disappear at the configured zoom levels; outside the band they are hidden, not garbled.
LBL-04 Turn on the Label Filter, Add Condition (e.g. road_class equals a value), and try several operators (equals, contains, begins with, comparison, is empty, is one of). Only matching features are labelled; the “VALUES IN FIELD” chips show distinct values with counts; Clear removes conditions.
LBL-05 Apply, pan/zoom hard, then reopen the project. Labels refresh without flicker or crash; all label settings (field, style, background, zoom range, filter) persist across reopen.

Definition Queries (Definition Filter)

Open Layer Details for Hamilton Parcels and find the Definition Filter section. A definition filter affects map rendering, labels, selection, snapping, search, and the table; in V1 export and analysis still use all committed features unless a tool’s selected-only option is used.

ID Step Expected result
FLT-01 Enable filter, Add Clause land_use equals residential, leave Match = AND. The map, table, and labels immediately show only residential parcels. The filtered-out parcels are hidden, not deleted.
FLT-02 Add a second clause and switch Match between AND and OR. AND narrows, OR widens, consistently between map and table. Domain-value chips show distinct values with counts.
FLT-03 Exercise operators: , contains, begins with, >, , <, , is empty, is not empty, is one of, is not one of. Each operator filters as described; the multi-value editor works for is one of / is not one of.
FLT-04 With a filter active, run an export and an analysis on the layer. The app makes clear (warning/copy) that export and analysis use all committed features in V1, or honors a selected-only scope — the active filter does not silently change exported/analyzed counts without notice.
FLT-05 Clear All, disable the filter, then reopen the project. The layer returns to all features. Re-enabling shows the saved clauses; filter state persists across reopen.

Field Management And Field Calculator

Open the attribute table / Layer Details for a layer to reach field tools. The recent build adds Convert Type and field rules; the Field Calculator creates or updates field values. Note: in this build there is no UI to add or delete an arbitrary field by hand — new fields are produced by the field calculator or by a typed Convert-Type output. Record that as a known limitation, not a failure.

ID Step Expected result
FLD-01 On a numeric column, open Convert Type and convert to/from Text/Integer/Decimal/Boolean. Review the Rows / Convertible / Null / Invalid metrics and before/after samples. Metrics and samples are accurate; invalid values map to null (not garbage). Choose Create Field for a new typed output or Replace existing field (with confirmation).
FLD-02 In Layer Details → Fields, set a field’s Required and Read-only rules and a Domain of allowed values; check the field type badge. Rules persist; the domain constrains values in the feature form; badges (Aa, 1, 1.2, TF, DATE, …) match the field type.
FC-01 Open Field Calculator. Mode Create fieldDecimal; Type GeometryArea on Hamilton Parcels. Preview, then Run. Preview shows sample results; Run creates a decimal field with plausible square-meter areas (matching area_sqm order of magnitude).
FC-02 Create another field with Type GeometryLength / Perimeter on roads/parcels as appropriate. Lengths/perimeters are plausible and in meters; no zeros or absurd values.
FC-03 Use Type Arithmetic (+ − × ÷ of two fields), Constant, Copy (from another field), and Concatenate (field + literal text). Each calculation writes correct values; Decimal, Integer, Boolean, Text, Date/Datetime, Object, and Array output types are respected.
FC-04 Make a selection, then run a calculation with Selected only ON. Only selected features change. The note about “All features includes filtered-out features” is shown when a definition filter is active; scope does not silently widen.
FC-05 Use Undo Last Calculation; then Open Table / Style Field shortcuts. Undo reverts the calculation cleanly; shortcuts open the table and symbology on the new field.
FC-06 Save, reopen, and export a layer with calculator-created fields. Calculated fields persist and export as normal attributes — with no editor-only/internal IDs in the output.

30 m School Buffer

ID Step Expected result
IP-11 Open Analysis and choose Buffer. Tool is available and not blocked by missing inputs. Method/warning copy is visible and understandable.
IP-12 Set input layer to Hamilton Schools, distance to 30, unit to meters, dissolve off, output name School 30m Buffer. Run. Analysis completes without errors. The original schools layer remains 7 point features. A new polygon layer appears with 7 buffer features.
IP-13 Visually inspect the buffer around Peachgrove Intermediate School. The buffer is a small local ring around the school point, not city-wide, not at 0,0, and not inverted by lon/lat order.
IP-14 Open the buffer attribute table. Table has 7 rows. Source school properties are present where expected. No raw scratch IDs or debug fields are visible to the user.
IP-15 Reopen Analysis History and the output layer details. The Buffer run is recorded with safe parameters: tool, input layer, 30 m distance, output name. No local absolute paths or credentials appear.
IP-16 Export School 30m Buffer as GeoJSON. Export succeeds. Exported GeoJSON is valid, contains polygon geometries, and omits editor-only IDs, draft IDs, scratch IDs, and internal storage metadata.
IP-17 Reimport the exported buffer into a new temporary project. Reimport succeeds as a normal polygon layer with 7 features. Geometry appears in the same Hamilton location.

Optional export spot check on Mac after moving the exported file there:

jq '.type, (.features | length), ([.features[].geometry.type] | unique)' School_30m_Buffer.geojson
rg -n "draft|scratch|selection_id|analysis_history|editor|internal" School_30m_Buffer.geojson

Expected: FeatureCollection, 7, polygon geometry types, and no matches for internal terms.

Planner Analysis Flow

ID Step Expected result
IP-18 Run Select by Location: target Hamilton Parcels, predicate intersects, selecting features that intersect School 30m Buffer. A non-zero parcel selection appears. Selected parcels cluster around the seven schools. The selected count matches the table’s selected scope. No schools or roads are selected by mistake.
IP-19 In the parcels table, switch between all rows and selected rows. Selected-only scope is clear. Row count and map highlight remain consistent.
IP-20 Run Summarize Within with School 30m Buffer as containers and Hamilton Parcels as input. Include area_sqm if field selection is shown. Output has 7 polygon features, one per buffer. Generated fields start with sw_. Counts/areas are non-negative and inspectable in the table.
IP-21 Run Network Reachability from Hamilton Schools over Hamilton Roads, with Hamilton Parcels as target, distance 250 m, unit meters, default snap/access settings. Reachable road output is created and at least some parcels are selected. Any start-snap warning explains that access distance counts toward the budget. Selected target distances, if shown, do not exceed the budget.
IP-22 Run Line Density on Hamilton Roads with a modest cell size and radius, such as 50 m cell size and 150 m radius. A square vector-grid polygon layer is created with density_value and method fields. Graduated styling appears on density_value. Output size stays under warning/block gates.
IP-23 Cancel a second longer analysis run shortly after starting. Cancellation returns control quickly, creates no partial committed output layer, and leaves existing layers untouched.
IP-24 Open Analysis History. Successful runs are listed with readable names and safe parameters. Cancelled runs do not look completed.

Full Analysis Tool Coverage

The Analysis panel exposes 22 tools across Selection, Geometry, Overlay, Proximity, Density, and Statistics, plus a Reproject Layer repair tool reachable when a layer’s source CRS is wrong. IP-11…IP-24 already cover Buffer, Select by Location, Summarize Within, Network Reachability, and Line Density. Run the remaining tools at least once each with the Hamilton fixtures (or the closest applicable inputs). For each, confirm: the run completes or fails cleanly, output geometry sits in Hamilton (never 0,0/swapped), the source layer is unchanged, Analysis History records safe parameters, and any size/feasibility gate behaves as documented.

ID Tool Step Expected result
ANA-01 Select by Attribute On parcels, select land_use = residential. A non-zero selection matching the table’s selected scope; choose selection / output layer / both as offered.
ANA-02 Feature to Point Convert Hamilton Parcels to points (centroid / point-on-surface / inscribed center). A point layer with one point per parcel, inside each parcel; attributes kept when “keep attributes” is on.
ANA-03 Snap Snap a copy of schools to Hamilton Roads within a tolerance. Output layer where in-tolerance points snap to road vertices/segments; out-of-tolerance points pass through unchanged (warning explains this).
ANA-04 Clip Clip Hamilton Roads to School 30m Buffer. Roads are trimmed to inside the buffer polygons only.
ANA-05 Multipart Dissolve Dissolve parcels, optionally by land_use. Adjacent same-value polygons merge; output count ≤ input; geometry stays valid.
ANA-06 Spatial Join Join parcels to School 30m Buffer (intersects). One row per match with joined fields; the large one-to-many expansion gate is respected (blocked/warned, not a runaway output).
ANA-07 Polygon Intersect Intersect parcels with School 30m Buffer. Output contains only the overlapping polygon pieces.
ANA-08 Polygon Erase Erase School 30m Buffer from parcels. Output is parcels with the buffer areas removed.
ANA-09 Polygon Union Union two polygon layers. Output partitioned into input-only / overlay-only / overlap pieces; same-layer overlap union is blocked/warned per the gate.
ANA-10 Merge Layers Merge two layers of compatible geometry into one. A single layer with a unified schema and the summed feature count.
ANA-11 Append to Layer Append a source (or selected-only) into an existing editable target. Features are added to the target, which is marked dirty; warning makes the in-place change explicit.
ANA-12 Nearest / Distance to Nearest From Hamilton Schools to Hamilton Roads. A point layer with non-negative nearest-distance values that look correct for Hamilton.
ANA-13 Point Density On Hamilton Schools with modest cell size/radius and output units. A square-grid polygon layer with density_value; cell-count warn (25k) / block (100k) gates honored.
ANA-14 Kernel Density On Hamilton Schools with a chosen bandwidth and output units. A smooth square-grid density surface; same 25k/100k gates; adaptive bandwidth is correctly absent (V1).
ANA-15 Summary Statistics On parcels, numeric fields with an optional group-by (land_use). A standalone table (not a layer) of descriptive stats; chart option appears when grouping yields multiple rows.
ANA-16 Reproject Layer (repair) If a layer reports a wrong source CRS, run the repair to the correct CRS. Geometry lands in the right place; CRS84 output is editable, other CRS are export-only as documented; a caution explains this is a repair tool. If no mis-CRS layer exists, record N/A.
ANA-17 Convex Hull On Hamilton Parcels, run Convex Hull with no group-by, then again with Group by = land_use. Ungrouped run yields one polygon wrapping all parcels; grouped run yields one hull per land_use value carrying the group value. hull_point_count is present. The hull sits over Hamilton, not 0,0.
ANA-18 Convex Hull (accuracy / degenerate) Run on a 1-feature selection, a 2-point selection, and a normal multi-point set; if you can, run on a deliberately broad/continental point set. 1 point → a Point + warning; 2 / collinear → a LineString + warning; ≥3 non-collinear → a Polygon. A broad extent attaches a visible “computed in planar lon/lat … not metrically exact” warning rather than failing. Antimeridian-spanning input is blocked with a clear error, never a wrong polygon. No zero-area fake polygon is emitted.
ANA-19 Select by Location (predicates) Beyond IP-18 (intersects), re-run Select by Location with each predicate — within, contains, touches — using Hamilton Parcels against School 30m Buffer, and try the Input/Overlay Selected Only scopes. Each predicate returns the expected feature set; result modes (selection / output layer / both) behave; selected-only scopes are honored and never silently widen. Same-layer input/overlay shows the documented “every feature matches itself” note.
ANA-20 After all runs, reopen Analysis History and reopen the project. Every successful run is listed with readable names and safe parameters (no absolute paths/credentials); cancelled runs never look completed; outputs persist across reopen.  

Charts (Chart Builder)

Open the Chart Builder. Charts can be built from a layer, a standalone table, or an analysis-output table, scoped to all filtered rows or selected only. Chart types: categorical bar, numeric histogram, summary bar, pie, box plot, line, scatter, density, and matrix heatmap. Charts are a read-only visualization surface — they never modify authoritative data.

ID Step Expected result
CHT-01 Build a categorical bar chart on Hamilton Parcels using land_use; then a histogram on area_sqm (try the bin-count slider). Bars/bins render with correct counts; the chart respects any active definition filter and flags itself stale when the filter changes. Truncation (e.g. top-N categories) is disclosed, not silent.
CHT-02 Build a pie, box plot, line, scatter, density, and matrix heatmap with appropriate fields; try a group-by where offered and a theme. Each chart type renders without crashing; group-by and theme apply; large series truncate gracefully with a visible note.
CHT-03 On a categorical bar / histogram / pie chart, tap a bar/slice (bucket) to drive selection linking. The matching features highlight on the map and in the table; the selected count matches; the highlight cap (e.g. truncated at the documented limit) is disclosed.
CHT-04 Make a map selection, set chart scope to Selected only, then switch back to All filtered. The chart recomputes for the selected features and back; scope is clearly labelled and never silently widens.
CHT-05 Build a chart from a Summary Statistics output table or another analysis output. The chart reads the analysis table correctly (matching ANA-15).
CHT-06 Export a chart as PNG/JPG/PDF/SVG. A clean image/document is produced with title and source/scope metadata; no editor-only IDs or internal metadata leak into the export.

Natural-Language Command Flow

The Command panel is a deterministic, fully on-device planner: it maps a typed request onto an existing tool/form and shows a reviewable plan, but never runs anything itself and never sends the query or project data off the device. These steps confirm that contract end to end.

ID Step Expected result
IP-C01 Open the Command panel (wand button in the top utilities, or ⌘K with a keyboard). A query field, example chips, and an empty/idle state appear. The map stays visible behind the Aero panel; no analysis runs on open.
IP-C02 With Wi-Fi off / airplane mode, type select residential parcels within 400 m walk of this school and submit. A plan card appears fully offline: tool = Network Reachability (or the documented reachability flow), resolved input/target layers shown, scope and units (400 m) read back, an output name, and a “Changes data / No data change” badge. Nothing has executed yet.
IP-C03 Apply the plan (“Open Analysis Setup” or equivalent verb). The matching analysis form opens already prefilled with the resolved layers, distance, and units — and is still fully editable. No tool runs until you confirm Run in the form.
IP-C04 Type calculate area for selected parcels (with a parcel selection active). Plan resolves to the Field Calculator with an area expression and the selected scope. Applying it opens the prefilled Field Calculator form; the selection scope matches the active selection and does not silently widen.
IP-C05 Type export selected schools to CSV with WKT. Plan resolves to an export of the schools layer scoped to the selection, CSV+WKT format. Applying opens the export flow prefilled; scoped export never silently widens to all features.
IP-C06 Type a deliberately ambiguous or unsupported request, e.g. do something with maps. The panel returns calm, actionable guidance (examples plus the project’s actual layer names), not a silent failure or a crash. No tool opens.
IP-C07 Type a request whose geometry cannot match, e.g. a line-only tool against a point layer. A clear warning explains the mismatch and the plan is blocked or redirected; no invalid tool run is offered.
IP-C08 Confirm no network activity occurred for any of IP-C02…IP-C07. With the network disabled the panel still works fully. The planner is local: no request, layer data, or attribute values leave the device.

Other Query Surfaces (Finder)

Beyond the Command panel, the Finder offers three modes: Find, Bookmarks, and Go To.

ID Step Expected result
FND-01 Open Finder → Find, search a value (e.g. Peachgrove) and switch scope between Visible, Editable, and All. Matches come from the scoped layers across attribute fields; results paginate/truncate gracefully (e.g. “first 100 matches”); selecting a result highlights and frames the feature.
FND-02 Save a Bookmark at the current extent, pan away, then return via the bookmark. The bookmark restores the saved center/zoom; it persists across reopen.
FND-03 Use Go To with a pasted coordinate. The map recenters on the coordinate with no lon/lat swap.

Drawing Geometry, Editing, And Snapping

The bottom tool dock offers Select (V), Point (P), Line (L), Polygon (G), Rect (R), Vertex (E), and Measure (M); Select includes Multi-select (Tap), Rectangle Select, and Lasso Select. During drawing the draw bar shows mode, point count, live metrics, snapping status, and Undo (⌘Z) / Cancel (Esc) / Finish (Return).

ID Step Expected result
DRW-01 Create a new editable point layer named Proposed Crossings with fields status and notes. An empty editable layer appears above the operational layers, clearly distinct from imported authoritative data.
DRW-02 Draw a Point, a Line, a Polygon, and a Rectangle into editable layers. Each geometry type draws correctly; the draw bar shows point count and metrics; Finish/Return commits, Esc cancels, ⌘Z removes the last vertex. Polygon closes correctly.
DRW-03 Configure Snapping: toggle on, set scope Active layer vs Visible layers, choose targets Endpoints / Vertices / Segments, and try tolerance Fine (10) / Standard (18) / Broad (30). Snapping engages only for the selected scope/targets; a tighter tolerance requires getting closer. Snap state is shown while drawing.
DRW-04 With snapping on, add a point near a road segment using Apple Pencil or touch; set status=proposed and a short note. Point snaps to the intended road/nearby vertex within tolerance; the feature form accepts attributes; the feature appears on the map.
DRW-05 Move the proposed point with Apple Pencil. Precision feedback shows coordinate, delta, bearing, and snap target type (Vertex/Edge/Midpoint/Split/No snap) while dragging. The map stays responsive.
DRW-06 Edit vertices: Vertex tool to move, insert, and delete a vertex on a drawn line/polygon; split a line; merge two features if offered. Each edit updates geometry correctly with snapping respected; invalid results are prevented or warned.
DRW-07 Use Measure to measure a distance and an area. Measurements read out in the configured units and match expectations for Hamilton scale.
DRW-08 Try multi-select: Tap, Rectangle Select, and Lasso Select. Each mode selects the intended features; the selected count is accurate.
DRW-09 Save edits, close the project, and reopen. Dirty state clears after save; all drawn geometry and attributes persist after reopen.
DRW-10 Create a validation issue if practical (invalid geometry / missing required field). Validation message is readable, non-technical, and blocks only the invalid save. Revert/cancel restores the last committed feature.
DRW-11 Delete a feature, cancel at the confirmation, then delete and confirm; exercise Undo/Redo. Cancel leaves the feature intact; confirm removes it from map and table; undo/redo restores/removes correctly.

Making Notes (Markup)

Markup notes are kept in a separate Markup layer role, distinct from authoritative GIS data, and must never leak into a data export as features. Markup types: Freehand, Arrow, Callout, Circle, Rectangle, Text.

ID Step Expected result
MRK-01 Add a Text note and a Callout note on the map. Notes place via an on-map flow, render as markup, and mark the project edited. They are clearly markup, not features in Hamilton Parcels/Roads/Schools.
MRK-02 Add Freehand, Arrow, Circle, and Rectangle markup; try the markup style presets. Each markup type draws and styles correctly; presets change stroke/fill.
MRK-03 Save, reopen, and export the data layers. Markup persists across reopen; a data export (e.g. GeoJSON of Hamilton Parcels) contains no markup geometry or note text.
MRK-04 Confirm markup appears in a PDF layout (see Layout section). Markup notes are included in the rendered PDF map where expected.

iPad Export, Layouts, Offline, Privacy, And Accessibility

ID Step Expected result
IP-31 Turn on airplane mode. Reopen the project. Project opens fully offline. Editable layers, imported layers, analysis outputs, and tables remain usable.
IP-32 Switch to no-basemap grid, then back to an online basemap after re-enabling network. No-basemap grid is usable and does not hide data. Online basemap reload does not clear selections or validation focus.
IP-31a Run Project Health and privacy scan. Healthy project reports no data-integrity errors. Clean fixture data reports no secrets.

Exporting Data: All Formats And The Export Inspector

Meridian exports data layers as GeoJSON, KML, KMZ, CSV+WKT (geometry-only or with attributes), GeoPackage (.gpkg), and Shapefile (.zip), and the whole project as a .gispad package. GeoJSON/KML/KMZ are locked to WGS84; GeoPackage/Shapefile/CSV+WKT offer a CRS choice. The Export Inspector is a pre-export validation/privacy scan.

ID Step Expected result
EXP-01 Export Hamilton Schools, School 30m Buffer, and a selected subset of Hamilton Parcels as GeoJSON (scoped where supported). Export succeeds; scoped export honors the selection and never silently widens; output is clean WGS84 GeoJSON.
EXP-02 Open the Export Inspector before confirming an export. It shows destination, included/excluded items, feature/field counts, attribution obligations, the Privacy section, and any blocking issues / warnings.
EXP-03 Export KML and KMZ for the schools layer. Files include layer folders/labels/styles; KMZ bundles marker icons; geometry lands in Hamilton.
EXP-04 Export CSV + WKT for one layer, both geometry-only and with attributes. The CSV has a WKT/WKP geometry column; attribute columns appear only when requested.
EXP-05 Export GeoPackage (.gpkg) for one layer; choose the CRS. A single WGS84 (or chosen-CRS) feature table is written; symbology/labels are not expected in .gpkg.
EXP-06 Export Shapefile (.zip) for one single-geometry layer; choose the CRS. A zipped .shp/.dbf/.prj is produced; field names shortened to 10 chars; single geometry type; reprojected to the chosen CRS.
EXP-07 For each exported file, confirm geometry and cleanliness. Editor-only/draft/scratch IDs, analysis-history IDs, internal metadata, absolute paths, and credentials are absent (see the X-06 rg check).
EXP-08 Share/export the .gispad project package. Share sheet appears; the package saves to Files and reopens as a full project with all layers/styles/edits intact.
EXP-09 If a connected source was added (IMP-08), export the .gispad package and inspect it. No service credential/token is written into the package or any export — credentials stay in the keychain only.

Layouts: Template PDF Map

Open the Layout tab. Templates: A4 Portrait/Landscape and US Letter Portrait/Landscape. Layout presets (Report Sheet, Field Handoff, Full-Bleed Map) one-click configure a framed or full-bleed page. Optional elements: Legend, Scale bar, North arrow, Date, Project, Subtitle, Notes, graticule/grid overlay, and Attribution (always on). Recent enhancements add per-element corner placement, scale-bar styles (line / bar / ratio), north-arrow styles (needle / compass), dynamic text tokens, legend options, export quality, and multi-page bookmark packets.

ID Step Expected result
LAY-01 Apply each preset (Report Sheet, Field Handoff, Full-Bleed Map), then create a one-page layout showing schools, 30 m buffers, roads, and parcels; set Title, Subtitle, and Notes. Each preset reconfigures the page (framed vs full-bleed) sensibly; the preview reflects the map and text; title/subtitle/notes render.
LAY-02 Toggle each element: Legend, Scale bar, North arrow, Date, Project, Attribution. Try the scale-bar style (line / bar / ratio) and north-arrow style (needle / compass). Each element shows/hides accordingly; Attribution cannot be turned off; the chosen scale-bar and north-arrow styles render. The legend matches current symbology.
LAY-03 Switch templates (A4 ↔ US Letter, Portrait ↔ Landscape) and set extent via Current Map / All Visible / Chosen Layer / Bookmark / Custom. Page size/orientation and framing update correctly without distorting the map; each extent mode frames as expected.
LAY-04 In Full-Bleed Map mode, set per-element corner placement (title, legend, scale bar, north arrow independently), card background (None/Frosted/Solid), drop shadow, and opacity. Each element moves to its chosen corner; cards restyle as set; text stays legible over the map.
LAY-05 Insert dynamic text tokens (e.g. {project_name}, {date}, {scale}, {crs_note}, {extent_label}) into the title/subtitle/notes. Tokens resolve to live values at render time, not literal placeholder text.
LAY-06 Set legend options: legend title, max items (with the “+N more” overflow), wrap-long-names, and per-layer show/hide in the legend. The legend honors the title, item cap/overflow, wrapping, and only the selected layers appear — without changing map visibility.
LAY-07 Add a graticule/grid overlay (graticule lines or edge ticks) with edge labels where available. The grid/ticks and degree labels render over the map and in the PDF without obscuring data.
LAY-08 Review the pre-export review checklist, choose export quality (Standard / High), then export the PDF (Share PDF / Save to Disk on Mac). Blocking items (missing title/attribution) are flagged before export; non-blocking warnings are advisory. A readable, correctly-sized PDF is produced with legend, scale, attribution intact and markup (MRK-04) where expected; High quality renders at higher resolution.
LAY-09 Set series mode to Bookmark Packet, choose several bookmarks, and export. A multi-page PDF is produced with one page per bookmark, each framed to its own extent with per-page extent label and scale.

Offline, Privacy, And Accessibility

ID Step Expected result
IP-38 With VoiceOver enabled, navigate Project Gallery, Layers, Symbology, Labels, Analysis, table rows, and the Export Inspector. Core icon-only controls have labels/hints. Active layer, selected feature, dirty state, validation, snapping, symbology mode, and export status are understandable.
IP-39 Test portrait, landscape, dark mode, and larger text. Floating chrome does not overlap critical map controls. Symbology/labels/analysis forms and tables remain usable; mono numbers stay legible.
IP-40 Rapidly pan/zoom for 60 seconds with all Hamilton layers visible and labels on. Map remains responsive, no memory warning appears, labels refresh without flicker/crash, and selected/buffer overlays stay aligned.

Mac Scenario: Desk Review And Parity

Run this on the native Mac app. For final App Store readiness, use a sandboxed Release archive or an installed exported app, not only Debug.

ID Step Expected result
MAC-01 Launch the Mac app from a clean sandbox/container. Gallery appears with no crash. Empty sandbox is understandable and not treated as data loss.
MAC-02 Create Hamilton School Access Review - Mac. Project opens to the shared workspace. Menus and toolbar commands match available actions.
MAC-03 Import the same three files from Resources/TestData/real-hamilton/. File picker grants access. Counts match iPad: parcels 2,193, roads 203, schools 7.
MAC-04 Recreate the same layer order, styles, and school labels. Visual result matches iPad closely enough for parity. Mac pointer affordances do not crowd the map.
MAC-04a Recreate a categorized/graduated symbology, a label filter, a definition filter, and a field-calculator field as on iPad. Symbology, labels, definition filter, and field calculator behave and persist equivalently to iPad.
MAC-05 Use trackpad/mouse pan, scroll zoom, and feature selection. Map movement is smooth. Hit testing selects the intended features with pointer-appropriate tolerance.
MAC-06 Use keyboard shortcuts for search/find, export/share, labels, basemap, delete selected feature, Return default actions, and Escape cancellation where available. Shortcuts trigger the same state changes as the visible UI and never bypass confirmation or validation.
MAC-07 Run the same Buffer analysis: Hamilton Schools, 30 m, meters, dissolve off, output School 30m Buffer. Output matches iPad expectations: 7 polygon features, same location, clean analysis history, source layer unchanged.
MAC-08 Run Select by Location from parcels intersecting School 30m Buffer. Non-zero selected parcel count. Count should match the iPad build for the same fixture and app version. If not, record both counts as a parity issue.
MAC-09 Run Network Reachability from schools over roads to parcels with the same 250 m settings used on iPad. Reachable road output and parcel selection are created. Selection count should match iPad for the same build or have an explained platform-specific input difference.
MAC-10 Create or edit one feature in an editable layer using pointer input. Pointer drag preview, snap feedback, validation, save, undo/redo, and delete behave equivalently to iPad storage/export behavior.
MAC-11 Open the attribute table for parcels and scroll from top to bottom. Table remains virtualized and responsive. Long names/values do not break row layout.
MAC-12 Export School 30m Buffer as GeoJSON to a user-selected folder. Sandboxed Release app can write to the selected folder. Output is valid and clean.
MAC-12a Export at least one layer in each remaining format — KML, KMZ, CSV+WKT, GeoPackage, Shapefile — to a user-selected folder, and review the Export Inspector. Each format writes a valid file with no internal IDs/credentials; the Export Inspector reports privacy/validation status.
MAC-13 Use Save PDF... from the Layout tab. PDF saves directly to the chosen folder and opens as a readable map page.
MAC-14 Export/share the .gispad package. Package saves successfully and can be reopened by the Mac app.
MAC-15 Quit and relaunch. Reopen the project. Project, layers, analysis outputs, styles, labels, and edits persist. No stale security-scoped file error blocks the project.
MAC-16 Open the iPad-exported .gispad package on Mac. Layers, feature counts, styles, analysis outputs, and edits match the iPad source project.
MAC-17 Export the Mac project package and open it on iPad. iPad opens the package with the same layer list, counts, map location, and clean export behavior.
MAC-18 Trigger an offline/no-network run with no-basemap grid. Local project open, editing, analysis, and export remain usable without network.
MAC-19 Check App Sandbox entitlements through real workflows: import from Downloads/Desktop, export to a chosen folder, reopen after relaunch. User-selected file read/write works. No broad file-system access is assumed.
MAC-20 Inspect menu items and disabled states while no project, one project, active selection, active edit session, and active analysis are present. Menu commands are enabled only when safe and match iPad command availability.

iPhone Scenario: Scoped Field Companion

Run this on a physical iPhone (ideally an older, smaller-screen device as well as a current one) using the closest-to-release universal build. The iPhone build is the scoped companion, not the full editor: it supports opening a project, browsing the map, toggling layer visibility, editing one feature’s attributes, dropping text/callout notes, and saving back with conflict handling. Heavy editing and analysis are deliberately iPad/Mac only — confirm those surfaces are simply absent on iPhone, not present-but-broken.

The phone routes to its own UI tree (PhoneRootView), so it needs an independent pass even though iPad/Mac are unchanged. If the iCloud container is not yet provisioned on the test device, the library shows Open from Files instead of iCloud projects — use that to load a .gispad package and run the same checks.

ID Step Expected result
PH-01 Launch Meridian on iPhone. A single-column phone project library appears quickly. No account or cloud sign-in prompt. Layout fits the phone (portrait), with no iPad chrome crammed in.
PH-02 Observe the library rows and document-state badges. If iCloud is available, projects list with a state badge (iCloud / Downloading / Downloaded / Edited / Conflict / Unavailable). Each badge pairs an icon and text — never color only. If iCloud is unavailable, a calm message offers Open from Files.
PH-03 Open a project (an iCloud project, or via Open from Files → a .gispad package such as the Hamilton review project). A working copy opens to a full-bleed map workspace with floating status pod, save affordance, bottom action cluster, and coordinate readout.
PH-04 Pan, zoom, and (if supported) tilt the map; then use “reset to flat north”. Map is responsive. The compass/reset control appears only when bearing or pitch is non-zero and returns to flat north without losing the center. Camera-only browsing does not mark the project dirty (save stays “Saved”).
PH-05 Open the Layers sheet and toggle a layer’s visibility. Visibility toggles are ≥44–48 pt and have a VoiceOver value (Visible/Hidden). The map updates immediately. Toggling visibility marks the document edited (Save affordance becomes active with a change count).
PH-06 Tap a feature on a visible, unlocked layer. The feature is selected and highlighted. The Inspect action becomes available in the bottom cluster. Taps only hit visible authoritative layers.
PH-07 Open the Feature Inspector. Shows an icon tile, a geometry summary (e.g. “Polygon · N vertices”), and a read-only field list. The Edit Attributes action is gated and explains calmly if the layer is hidden or locked.
PH-08 Edit attributes on an editable feature: change a field value and Save. The attribute form opens prefilled with current values, with per-field controls (picker/toggle/typed field). Save commits the edit, refreshes the feature, and marks the document edited. Cancel discards cleanly.
PH-09 Add a text note: choose Add note → Text, place it on the map, type, and confirm. A placement banner guides the tap; the note is added as markup, appears on the map, and marks the document edited. The note is markup, not authoritative layer data.
PH-10 Add a callout note. Callout places with a fixed short leader (no target-pick UI in this release — acceptable). Note is added and persists.
PH-11 Save the project (Save affordance → publish to iCloud). Save shows a spinner then a “Saved” confirmation/toast; the change count clears and the document state returns to clean. With iCloud unavailable this path is exercised only where Open-from-Files allowed a writable copy.
PH-12 Force a conflict if possible (edit and save the same iCloud project from iPad/Mac while the phone holds an edited copy), then save on the phone. The Conflict Resolution sheet appears with clear choices: Save as Conflict Copy, Keep Editing Locally, or the destructive Reload-discards-local. Choosing Save as Conflict Copy preserves both versions; neither loses data silently.
PH-13 Confirm scope: look for full editing/drawing/analysis tools. The iPad-only drawing toolset, geometry editing, and the 20-tool analysis surface are absent on iPhone (scoped companion), not shown-but-failing. Back navigation returns to the library.
PH-14 Reopen the project after saving. Layer visibility, attribute edits, notes, and camera persist. No data loss, no editor-only IDs introduced.
PH-15 With VoiceOver on, navigate the library, badges, map chrome, Layers sheet, and Inspector/attribute form. Icon-only controls have labels/hints. Document state, selection, dirty state, and conflict actions are understandable without sight.
PH-16 Test portrait, dark mode, and larger text on iPhone. Floating chrome does not overlap critical controls. Library rows, sheets, and forms remain usable; mono numbers stay legible.

Parity note: a project edited on iPhone and saved must reopen correctly on iPad/Mac (and vice versa) — covered by X-05/X-08 below.

Cross-Platform Data Integrity Checks

After the iPad and Mac runs, compare the exported artifacts.

ID Check Expected result
X-01 Compare imported layer counts across platforms. Schools 7, roads 203, parcels 2,193 on both platforms.
X-02 Compare School 30m Buffer output counts. 7 polygon features on both platforms when dissolve is off.
X-03 Compare selected parcel counts from the same Select by Location settings. Counts match across platforms for the same build and fixture.
X-04 Compare Network Reachability selected parcel counts from the same settings. Counts match across platforms for the same build and fixture.
X-05 Reopen each platform’s .gispad export on the other platform. No missing layers, wrong geometry types, lost edits, broken styles, or corrupt project-health warnings.
X-06 Search exported GeoJSON for internal terms. No draft, scratch, selection_id, analysis_history, editor, internal, absolute local path, API key, token, or credential-bearing URL appears unless it is a legitimate user attribute deliberately added for testing.
X-07 Validate coordinate ranges in exports. Hamilton coordinates remain WGS84 lon/lat around 175.x, -37.x; no lat/lon swap and no rounded integer coordinate loss.
X-08 Edit a project on iPhone (layer visibility, one attribute, a note), save, then reopen it on iPad and Mac; and open an iPad/Mac project on iPhone. All three platforms see the same layers, counts, geometry, styles, edits, and notes. No editor-only IDs leak into any export. Document revision/conflict handling keeps both sides consistent.

Useful export checks:

jq '.features | length' exported.geojson
jq '[.. | arrays | select(length == 2 and (.[0] | type == "number") and (.[1] | type == "number"))] | {lon_min: (map(.[0]) | min), lon_max: (map(.[0]) | max), lat_min: (map(.[1]) | min), lat_max: (map(.[1]) | max)}' exported.geojson
rg -n "draft|scratch|selection_id|analysis_history|editor|internal|api[_-]?key|token|/Users/|/var/folders" exported.geojson

Store-Readiness Acceptance Notes

Before submission, write a short release note for the evidence folder:

The final App Store submission can proceed only when all P0 items pass and every P1 has either a fix, a retest, or an explicit release-risk acceptance.