Skip to content

Conversation

@mattpodwysocki
Copy link
Contributor

@mattpodwysocki mattpodwysocki commented Jan 8, 2026

Summary

Implements a comprehensive style comparison tool that performs deep structural comparison of two Mapbox styles, identifying additions, removals, and modifications.

Key Features

  • Deep Object Comparison: Recursively compares nested structures with detailed diff reporting
  • Layer Comparison by ID: Compares layers by their ID property rather than array index
  • Metadata Filtering: Optional ignoreMetadata flag to ignore metadata fields (id, owner, created, modified, draft, visibility)
  • Flexible Input: Accepts JSON strings or objects for both styles
  • Structured Output: Returns differences with JSON paths, types (added/removed/modified), and descriptive messages

Implementation Details

  • Extends BaseTool for offline operation (no API calls required)
  • Special handling for Mapbox style layers ensures correct comparison even when layer order changes
  • Comprehensive error handling for invalid JSON input
  • Full Zod schema validation for inputs and outputs

Testing

  • 16 comprehensive test cases covering:
    • Tool metadata validation
    • Identical styles detection
    • Property differences (added, removed, modified)
    • Layer differences with ID-based comparison
    • Metadata handling with ignoreMetadata flag
    • JSON string input parsing
    • Error handling for invalid JSON
    • Nested property change detection
    • Summary statistics validation

All tests passing ✅

Documentation

Added comprehensive README documentation for all three validation tools:

Each tool is documented with parameters, features, return values, and example prompts.

Testing

Test 1: Identical Styles

Purpose: Verify that two identical styles are detected as identical

Prompt to Claude:
Compare these two Mapbox styles using compare_styles_tool:

Style A:

  {
    "version": 8,
    "name": "Basic Style",
    "sources": {
      "mapbox-streets": {
        "type": "vector",
        "url": "mapbox://mapbox.mapbox-streets-v8"
      }
    },
    "layers": [
      {
        "id": "background",
        "type": "background",
        "paint": {"background-color": "#f0f0f0"}
      }
    ]
  }

Style B: (same as Style A)

  {
    "version": 8,
    "name": "Basic Style",
    "sources": {
      "mapbox-streets": {
        "type": "vector",
        "url": "mapbox://mapbox.mapbox-streets-v8"
      }
    },
    "layers": [
      {
        "id": "background",
        "type": "background",
        "paint": {"background-color": "#f0f0f0"}
      }
    ]
  }

Expected Result:

  • identical: true
  • differences: []
  • summary.totalDifferences: 0
Screenshot 2026-01-09 at 18 32 26

Test 2: Color Change in Layer

Purpose: Detect a modified paint property

Prompt to Claude:
Compare these two styles where the background color changed:

Style A:

  {
    "version": 8,
    "name": "Test Style",
    "sources": {},
    "layers": [
      {
        "id": "background",
        "type": "background",
        "paint": {"background-color": "#f0f0f0"}
      }
    ]
  }

Style B:

  {
    "version": 8,
    "name": "Test Style",
    "sources": {},
    "layers": [
      {
        "id": "background",
        "type": "background",
        "paint": {"background-color": "#e0e0e0"}
      }
    ]
  }

Expected Result:

  • identical: false
  • differences should contain one item with:
    • path: "layers.background.paint.background-color"
    • type: "modified"
    • valueA: "#f0f0f0"
    • valueB: "#e0e0e0"
  • summary.modified: 1
Screenshot 2026-01-09 at 18 35 37

Test 3: Layer Added

Purpose: Detect when a new layer is added

Prompt to Claude:
Compare these styles where Style B has an additional water layer:

Style A:

  {
    "version": 8,
    "name": "Test",
    "sources": {"mapbox-streets": {"type": "vector", "url": "mapbox://mapbox.mapbox-streets-v8"}},
    "layers": [
      {"id": "background", "type": "background", "paint": {"background-color": "#fff"}}
    ]
  }

Style B:

  {
    "version": 8,
    "name": "Test",
    "sources": {"mapbox-streets": {"type": "vector", "url": "mapbox://mapbox.mapbox-streets-v8"}},
    "layers": [
      {"id": "background", "type": "background", "paint": {"background-color": "#fff"}},
      {"id": "water", "type": "fill", "source": "mapbox-streets", "source-layer": "water", "paint": {"fill-color": "#a0c8f0"}}
    ]
  }

Expected Result:

  • identical: false
  • differences should show the water layer was added
  • summary.added: 1 (or more depending on how it counts nested properties)
Screenshot 2026-01-09 at 18 36 46

Test 4: Layer Removed

Purpose: Detect when a layer is removed

Prompt to Claude:
Compare these styles where the water layer was removed in Style B:

Style A:

  {
    "version": 8,
    "name": "Test",
    "sources": {"mapbox-streets": {"type": "vector", "url": "mapbox://mapbox.mapbox-streets-v8"}},
    "layers": [
      {"id": "background", "type": "background", "paint": {"background-color": "#fff"}},
      {"id": "water", "type": "fill", "source": "mapbox-streets", "source-layer": "water", "paint": {"fill-color": "#a0c8f0"}}
    ]
  }

Style B:

  {
    "version": 8,
    "name": "Test",
    "sources": {"mapbox-streets": {"type": "vector", "url": "mapbox://mapbox.mapbox-streets-v8"}},
    "layers": [
      {"id": "background", "type": "background", "paint": {"background-color": "#fff"}}
    ]
  }

Expected Result:

  • identical: false
  • differences should show the water layer was removed
  • summary.removed: 1 (or more)
Screenshot 2026-01-09 at 18 38 25

Test #5: Metadata Changes with ignoreMetadata=true

Purpose: Verify that metadata fields can be ignored

Prompt to Claude:
Compare these styles with ignoreMetadata=true. They differ only in metadata:

Style A:

  {
    "version": 8,
    "id": "style-v1",
    "owner": "user1",
    "created": "2024-01-01",
    "modified": "2024-01-01",
    "name": "Test Style",
    "sources": {},
    "layers": []
  }

Style B:

  {
    "version": 8,
    "id": "style-v2",
    "owner": "user2",
    "created": "2024-01-02",
    "modified": "2024-01-02",
    "name": "Test Style",
    "sources": {},
    "layers": []
  }

Use ignoreMetadata: true

Expected Result:

  • identical: true (because metadata is ignored)
  • differences: []
Screenshot 2026-01-09 at 18 39 29

Test #6: Metadata Changes with ignoreMetadata=false

Purpose: Verify that metadata differences are detected when not ignored

Prompt to Claude:
Compare the same styles from Test #5, but with ignoreMetadata=false or omitted.

Expected Result:

  • identical: false
  • differences should show changes to id, owner, created, modified fields
  • summary.modified: 4 (one for each metadata field)
Screenshot 2026-01-09 at 18 40 57

Test #7: Layer Reordering (ID-based comparison)

Purpose: Verify that layers are compared by ID, not array position

Prompt to Claude:
Compare these styles where layers are in different order:

Style A:

  {
    "version": 8,
    "name": "Test",
    "sources": {"mapbox-streets": {"type": "vector", "url": "mapbox://mapbox.mapbox-streets-v8"}},
    "layers": [
      {"id": "water", "type": "fill", "source": "mapbox-streets", "source-layer": "water", "paint": {"fill-color": "#a0c8f0"}},
      {"id": "background", "type": "background", "paint": {"background-color": "#fff"}}
    ]
  }

Style B:

  {
    "version": 8,
    "name": "Test",
    "sources": {"mapbox-streets": {"type": "vector", "url": "mapbox://mapbox.mapbox-streets-v8"}},
    "layers": [
      {"id": "background", "type": "background", "paint": {"background-color": "#fff"}},
      {"id": "water", "type": "fill", "source": "mapbox-streets", "source-layer": "water", "paint": {"fill-color": "#a0c8f0"}}
    ]
  }

Expected Result:

  • identical: true (layers are the same, just reordered)
  • OR if order matters, should show modifications to layer positions
Screenshot 2026-01-09 at 18 42 06

Related PRs

Part of the offline validation tools initiative:

Implements a comprehensive style comparison tool that performs deep
structural comparison of two Mapbox styles, identifying additions,
removals, and modifications in layers, sources, and properties.

Key features:
- Deep object comparison with detailed diff reporting
- Layer comparison by ID instead of array index
- Metadata filtering (ignoreMetadata flag)
- Support for JSON strings or objects as input
- Structured output with difference paths and summaries

The tool extends BaseTool for offline operation (no API calls).
Special handling for Mapbox style layers ensures layers are compared
by their ID property rather than position in the array.

Test coverage: 16 comprehensive test cases covering all features
including identical detection, property/layer differences, metadata
handling, error cases, and nested changes.

Documentation: Added comprehensive README documentation for all three
validation tools (validate_geojson_tool, validate_expression_tool,
compare_styles_tool) with usage examples and feature descriptions.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@mattpodwysocki mattpodwysocki requested a review from a team as a code owner January 8, 2026 20:40
mattpodwysocki added a commit that referenced this pull request Jan 9, 2026
…roduction prompt

Adds comprehensive style quality validation capabilities:

Skill:
- Created mapbox-style-quality skill document (390+ lines)
- Pre-production checklist and validation best practices
- Guidance on expression validation, GeoJSON validation, and accessibility
- Optimization strategies and workflow recommendations
- Integration patterns for Git hooks, CI/CD, and code review

Prompt:
- Created prepare-style-for-production prompt
- Orchestrates validation workflow using 5 quality tools:
  * validate_expression_tool - Validate expressions in filters/paint/layout
  * validate_geojson_tool - Validate GeoJSON sources
  * check_color_contrast_tool - WCAG accessibility compliance
  * optimize_style_tool - Remove redundancies and optimize
  * compare_styles_tool - Compare versions (implicit in workflow)
- Configurable WCAG level (AA/AAA) and optional optimization skip
- Generates comprehensive quality report with deployment readiness assessment

Testing:
- 15 test cases for PrepareStyleForProductionPrompt
- All 386 tests passing
- Updated prompt registry tests

Documentation:
- Updated README with new skill listing
- Added prompt documentation with usage examples
- Cross-referenced skill and prompt

Related PRs:
- PR #50: validate_geojson_tool
- PR #51: validate_expression_tool
- PR #52: compare_styles_tool
- PR #53: check_color_contrast_tool
- PR #54: optimize_style_tool

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
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.

1 participant