Skip to content

Implement point-in-zone classifier tool (E03 step 4)#269

Open
IanMayo wants to merge 26 commits intomainfrom
claude/speckit-start-081-3Btda
Open

Implement point-in-zone classifier tool (E03 step 4)#269
IanMayo wants to merge 26 commits intomainfrom
claude/speckit-start-081-3Btda

Conversation

@IanMayo
Copy link
Member

@IanMayo IanMayo commented Feb 18, 2026

Summary

Implement the point-in-zone classifier tool — step 4 of the E03 buffer zone analysis chain. This tool classifies reference points by testing each coordinate against concentric detection zone polygons using a ray-casting point-in-polygon algorithm, then updates per-point metadata with zone assignment and color.

Key Changes

Specification & Documentation

  • Feature specification at specs/081-point-in-zone-classifier/spec.md with 3 user stories and 14 functional requirements
  • Tool specification at shared/tools/reference/classification/point-in-zone-classifier.1.0.md covering algorithm, inputs, outputs, and annotations
  • Golden example pairs (basic classification + all-outside scenarios) with input/output JSON files
  • Supporting documentation: research decisions, data model, tool contract, quickstart, and implementation plan

Python Implementation

  • services/calc/debrief_calc/tools/reference/classification.py — core tool implementation with:
    • _point_in_polygon(): Ray-casting algorithm for point-in-polygon testing
    • point_in_zone_classifier(): Main classifier function registered via @tool decorator with ContextType.MULTI
    • Innermost-first zone priority (most specific zone wins)
    • Metadata preservation and extension with zone and color fields
    • pointColors array generation for per-point rendering
  • Tool registration in services/calc/debrief_calc/tools/reference/__init__.py and services/calc/debrief_calc/tools/__init__.py

TypeScript Implementation

  • apps/vscode/src/tools/reference/classification/pointInZoneClassifier.ts — identical algorithm in TypeScript with:
    • Ray-casting point-in-polygon implementation
    • Zone classification with innermost-first priority
    • Metadata preservation and color assignment
  • Barrel export at apps/vscode/src/tools/reference/classification/index.ts
  • Tool registration in apps/web-shell/src/services/toolService.ts

Comprehensive Test Suite

  • services/calc/tests/tools/reference/test_classification.py — 22 tests covering:
    • TestClassifyBasic (7 tests): Zone assignment, point colors array, innermost-first priority
    • TestMetadataPreservation (4 tests): Field preservation, reclassification, immutability
    • TestDeterminism (2 tests): Reproducibility and geometry preservation
    • TestEdgeCases (7 tests): Missing features, invalid geometry, metadata mismatches, empty inputs
    • TestGoldenExamples (2 tests): Validation against golden I/O files

Implementation Details

  • Algorithm: Ray-casting (even-odd rule) for O(n) point-in-polygon testing per point
  • Zone Priority: Tests zones innermost-first; first match wins (prevents outer zones from overriding inner)
  • Metadata Handling: Deep copies input metadata, preserves all existing fields, adds/updates zone and color
  • Color Mapping: Extracts from zone metadata style.fill_color (preferred) or style.color; defaults to #666666 for points outside all zones
  • Dependencies: Stdlib only (no external geometry libraries) — Constitution Article I (offline) and Article IX (minimal dependencies) compliant
  • Performance: Classifies 10,000 points against 3 zones in < 1 second

All 22 tests passing. Zero external dependencies. Ready for integration with generate-reference-points (#78) and buffer-zone-generator (#80).

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG

Create feature spec and tool spec for the point-in-zone classifier,
step 4 of the E03 buffer zone analysis cascade. The tool classifies
MultiPoint reference coordinates against concentric detection zone
polygons using ray-casting, updating per-point metadata with zone
name and color for visual rendering.

Includes 2 golden I/O examples (basic classification and all-outside).

Links to specs/081-point-in-zone-classifier/spec.md

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
Phase 0: research.md — algorithm decisions (ray-casting, no external deps)
Phase 1: data-model.md, contracts/tool-contract.yaml, quickstart.md
Phase 1: plan.md with constitution check (all pass), project structure
Phase 2: media/planning-post.md, media/linkedin-planning.md

All constitution gates pass. No new technologies introduced.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
Python and TypeScript implementations of the point-in-zone classifier,
step 4 of the E03 buffer zone analysis chain. Classifies MultiPoint
reference coordinates against concentric detection zone polygons using
ray-casting algorithm with innermost-first zone priority.

Changes:
- Python: services/calc/debrief_calc/tools/reference/classification.py
- TypeScript: apps/vscode/src/tools/reference/classification/
- Registration: Python @tool, web-shell Map, VS Code barrel
- Tests: 22 Python tests (all passing), golden example validation
- Evidence: test-summary.md, usage-example.md
- Media: shipped-post.md, linkedin-shipped.md

Zero external dependencies. Stdlib only in both languages.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
@github-actions
Copy link

github-actions bot commented Feb 18, 2026

🚀 Preview Deployments

Code Server (Full VS Code Extension)

🖥️ Open Code Server

Browser-based VS Code with the Debrief extension and sample data pre-installed.

Web Shell (Standalone App)

📱 Open Web Shell

Use this for Playwright testing and demos - runs outside Storybook.

Storybook (Component Library)

📚 Open Storybook

Browse all components, stories, and documentation.


All Links
Environment Code Server Web Shell Storybook
This PR Open IDE Open App Open Storybook
Main branch Open App Open Storybook

Updated on commit c7cadce

claude and others added 13 commits February 19, 2026 20:52
Remove unused ToolParameter import, add strict=True to zip() calls,
rename unused loop variable e to _e.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
Display truncated feature ID (first 8 chars) in the info area of each
feature row. Helps diagnose duplicate ID issues when multiple features
of the same type appear selected.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
Adds a circled-i icon button on each feature row (visible on hover).
Clicking it shows an alert dialog listing all feature properties
including the feature ID, kind, geometry type, etc. Helps diagnose
duplicate ID issues.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
Clicking the info text on a FeatureRow now opens an alert dialog
showing the full feature id plus all properties and geometry type.
Removes redundant separate info-icon button.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
Adds a Leaflet bindPopup to onEachFeature that displays feature.id
as the first line, followed by scalar properties and geometry type.
This helps diagnose a suspected duplicate ID issue when selecting
reference points and detection zone features together.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
- Add bindPopup mock to 3 test files (MapView.test, selection.test,
  selection-sync.test) to match MapView's new popup feature
- Add vscrui as direct dependency of apps/vscode so esbuild can
  resolve codicon.css during webview bundling
- Allow esbuild/keytar/@vscode/vsce-sign build scripts in pnpm
- Handle provenance/input_state as schema-pending fields in JS
  golden fixture validation (fields defined in LinkML but not yet
  wired into per-feature property classes)
- Fix flaky layer selection E2E tests by replacing non-retrying
  count assertions with Playwright's auto-retrying toHaveCount()

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
Add `-> None` return type annotations to all 22 test methods in
test_classification.py. Fix circle-annotation-input-state-01.json
fixture to use snake_case property names and array-format parameters
matching the generated LogEntry/WasGeneratedBy schemas.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
Use float literals in coordinate ring definitions to match the
`list[list[list[list[float]]]]` parameter type of `_make_zone_feature`.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
@IanMayo IanMayo temporarily deployed to debrief-preview-pr-269 March 6, 2026 15:59 Inactive
@IanMayo IanMayo temporarily deployed to debrief-preview-pr-269 March 6, 2026 16:02 Inactive
Add zone spacing presets (small: 1/2/4 nm, medium: 2/4/8 nm,
large: 3/6/12 nm) to both Python and TypeScript implementations.
Explicit distance_*_nm parameters still override the interval.
Update tool spec with interval parameter docs and changelog.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
@IanMayo IanMayo temporarily deployed to debrief-preview-pr-269 March 6, 2026 16:32 Inactive
Replace the stub toast message in the layer:delete handler with
actual deletion by setting the selection and executing the existing
debrief.deleteSelection command.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
@IanMayo IanMayo temporarily deployed to debrief-preview-pr-269 March 6, 2026 16:38 Inactive
Result layers from tool execution (e.g., Buffer Zone Generator) were not
appearing in the Layers listing until page refresh, because MapPanel.addResultLayer()
only sent layers to the map webview but never notified the ActivityPanelViewProvider.

Also fixes getFeatureKind() to search inside result layer features instead of
returning 'RESULT' for layer IDs or undefined for individual feature IDs. This
enables tool matching (e.g., Point in Zone Classifier) to see the correct kind
(POINT, ZONE) for result features.

Changes:
- Add syncActivityPanelFeatures() helper that combines source + result features
- Call it from addResultLayer() and removeFeatures()
- Update getFeatureKind() to look up individual features within result layers

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
@IanMayo IanMayo temporarily deployed to debrief-preview-pr-269 March 6, 2026 17:11 Inactive
…output_kind

The executor/toolService was overwriting feature.properties.kind with the
tool's output_kind value (e.g., "addition/feature", "reference/generated_points")
after the Python tool had already set it correctly (e.g., "ZONE", "POINT").

This caused:
- Wrong type badges in the Layers listing (showing result types instead of kinds)
- Point in Zone Classifier not recognizing result features as POINT or ZONE

Fix: set_output_kind() and its TS equivalent now only set kind when the feature
doesn't already have one, preserving tool-assigned domain-specific kinds.
Also relaxes validation to accept any kind (not just expected_kind).

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
@IanMayo IanMayo temporarily deployed to debrief-preview-pr-269 March 6, 2026 17:23 Inactive
…colors

Two bugs fixed in the point-in-zone classifier workflow:

1. Duplicate layer: classifier deep-copied the input feature preserving
   its ID, causing two features with the same ID in the layers panel.
   Hiding one hid both. Now assigns "{baseId}-classified" and appends
   "(classified)" to the name.

2. No zone shading: pointToLayer used a single color for all MultiPoint
   coordinates. Now looks up per-point colors from the pointColors array
   by matching latlng back to the coordinate index.

https://claude.ai/code/session_01EWe9YQXUrUdynXavqEZUmG
@IanMayo IanMayo temporarily deployed to debrief-preview-pr-269 March 6, 2026 17:49 Inactive
…081-3Btda

# Conflicts:
#	shared/schemas/src/fixtures/valid/circle-annotation-input-state-01.json
#	shared/schemas/tests/validate-jsonschema.js
@IanMayo IanMayo temporarily deployed to debrief-preview-pr-269 March 8, 2026 09:22 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants