Skip to content

Drive trait schema enums from PreviewTraits canonical lists#164

Merged
obj-p merged 2 commits intomainfrom
worktree-schema-dsl
May 6, 2026
Merged

Drive trait schema enums from PreviewTraits canonical lists#164
obj-p merged 2 commits intomainfrom
worktree-schema-dsl

Conversation

@obj-p
Copy link
Copy Markdown
Owner

@obj-p obj-p commented May 6, 2026

Summary

Step #5 of the architectural-refactor roadmap. The previous shape duplicated the 12-string `dynamicTypeSize` enum verbatim across `previewStart` and `previewConfigure` schemas — adding a new value meant editing `PreviewTraits` plus both schemas, with no test catching a forgotten edit.

After the refactor, both schemas reference `PreviewTraits.validColorSchemes` / `validDynamicTypeSizes` / `validLayoutDirections` / `validLegibilityWeights` directly. Adding a new value touches one place (`PreviewTraits`) and both schemas pick it up automatically.

Changes

  • `PreviewTraits.swift`: convert the four `valid*` constants from `Set` to ordered `[String]`. Order matters because the schema enum arrays are wire-relevant (the `ListToolsSnapshotTests` byte-snapshot pins array order in JSON). Internal callers (`.contains` for validation, `.union` in `allPresetNames`) all work on arrays or are wrapped with `Set(...)`.
  • New `Handlers/TraitPropertySchema.swift` with a small `traitProperty(enumValues:description:)` helper that builds the consistent `{type, enum, description}` Value shape. Descriptions stay per-handler since `previewStart` and `previewConfigure` legitimately say different things ("override" suffix vs "Pass empty string to clear" suffix).
  • `PreviewStartHandler.swift` and `PreviewConfigureHandler.swift`: trait property literals replaced with `traitProperty(enumValues: PreviewTraits.validX, description: ...)` calls.

Acceptance gate

  • `ListToolsSnapshotTests` passes — the JSON-encoded `ListTools` response is byte-identical pre/post (the `Tests/PreviewsCLITests/list_tools_snapshot.json` fixture from Split MCPServer.swift into per-tool handler files behind ToolHandler #162 didn't change).
  • New `TraitSchemaTests` asserts both handlers' enum constraints match the canonical `PreviewTraits` arrays. Catches the realistic regression: adding a value to `PreviewTraits` but forgetting to pick it up in a schema.

What's NOT changed

  • Trait extraction in `parseTraits` (in `MCPServerSupport.swift`) still names the 5 trait fields explicitly. `PreviewTraits.validated` takes 5 named parameters; refactoring that requires a deeper PreviewsCore API change. Out of scope.
  • Asymmetric `enum` enforcement: `previewConfigure` deliberately doesn't enforce `enum` on `layoutDirection` / `legibilityWeight` (it accepts empty-string-as-clear). Preserved.

Test plan

  • `swift build` clean
  • `swift-format format --in-place --recursive Sources/ Tests/PreviewsCLITests/` clean
  • `swift test --filter ListToolsSnapshotTests` — wire bytes match
  • `swift test --filter TraitSchemaTests` — 3 new tests pass
  • `swift test --filter MacOSMCPTests` — 7 tests pass (including `structuredContent payloads decode for each migrated tool` and the variants test)
  • `swift test --filter PreviewsCoreTests` — 246 tests pass (including `BridgeGeneratorTraitsTests.validColorSchemes` and `validDynamicTypeSizes` which compare against the now-Array constants)

🤖 Generated with Claude Code

obj-p and others added 2 commits May 6, 2026 07:58
Step #5 of the architectural roadmap. The previous shape duplicated
the 12-string `dynamicTypeSize` enum verbatim across `previewStart` and
`previewConfigure` schemas — adding a new dynamic type size meant
editing PreviewTraits + both schemas, with no test catching a
forgotten edit.

Convert `PreviewTraits.validColorSchemes`, `validDynamicTypeSizes`,
`validLayoutDirections`, `validLegibilityWeights` from `Set<String>` to
ordered `[String]` so they can drive both validation (via `.contains`)
and the wire-relevant `enum` arrays in MCP tool schemas (the snapshot
test pins the array order in JSON). Add a small `traitProperty(...)`
helper in `Sources/PreviewsCLI/Handlers/TraitPropertySchema.swift` that
builds the consistent `{type, enum, description}` shape — descriptions
stay per-handler since `previewStart` and `previewConfigure` legitimately
say different things ("override" vs "Pass empty string to clear").

Behavior preserved: `ListToolsSnapshotTests` confirms wire bytes are
identical pre/post.

New `TraitSchemaTests` asserts both handlers' enum constraints match
the canonical PreviewTraits arrays. Catches the realistic regression:
adding a value to PreviewTraits but forgetting to pick it up in a
schema. Doesn't catch a contributor copy-pasting the literals inline
with matching values — that's a source-level concern beyond runtime
testing, and the snapshot test catches any value drift anyway.

The Set→Array conversion is a public API shape change in PreviewsCore.
Internal usage (`.contains`, `.union`, `.sorted`) all work on arrays
or are easily wrapped in `Set(...)` (only `allPresetNames` needed an
update). External usage in `BridgeGeneratorTraitsTests` continues to
pass — its `==` comparison was already against ordered literals.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two small polish items from the code-reviewer pass:

- `traitProperty(...)`: drop the `Dictionary(uniqueKeysWithValues:)`
  ceremony. Key insertion order is irrelevant because the JSONEncoder
  used by `ListToolsSnapshotTests` outputs sorted keys — the tuple
  ordering was inert and invited confusion.
- `PreviewTraits.valid*` doc: lead with the wire-shape rationale
  (why arrays, not Sets) and mention O(n) `.contains` as a
  consequence rather than a separate sentence.

No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@obj-p obj-p merged commit 03e2b51 into main May 6, 2026
4 checks passed
@obj-p obj-p deleted the worktree-schema-dsl branch May 6, 2026 12:39
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