|
1 | 1 | # Combinators Implementation Plan |
2 | 2 |
|
3 | | -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. |
| 3 | +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [x]`) syntax for tracking. |
4 | 4 |
|
5 | 5 | **Goal:** Implement runtime validation for OpenAPI 3.1 combinators (`allOf`, `anyOf`, `oneOf`, `not`) and let combinators co-exist with sibling base assertions (`type`, `properties`, etc.) per JSON Schema 2020-12. |
6 | 6 |
|
|
22 | 22 |
|
23 | 23 | ### Step 1.1: Write failing validator tests |
24 | 24 |
|
25 | | -- [ ] **Step 1: Add tests for combinator validation** |
| 25 | +- [x] **Step 1: Add tests for combinator validation** |
26 | 26 |
|
27 | 27 | Replace the existing `combinatorThrowsUnsupported` test in `src/test/java/com/retailsvc/http/validate/DefaultValidatorDispatchTest.java` with the following block (delete the old test, append the new ones at the end of the class). Keep the existing imports and add: `AllOfSchema`, `AnyOfSchema`, `NotSchema`, `StringSchema`. |
28 | 28 |
|
@@ -124,15 +124,15 @@ void notFailsWhenInnerPasses() { |
124 | 124 | } |
125 | 125 | ``` |
126 | 126 |
|
127 | | -- [ ] **Step 2: Run the failing tests** |
| 127 | +- [x] **Step 2: Run the failing tests** |
128 | 128 |
|
129 | 129 | Run: `mvn -q test -Dtest=DefaultValidatorDispatchTest` |
130 | 130 |
|
131 | 131 | Expected: 9 new tests fail with `UnsupportedOperationException` (and the old `combinatorThrowsUnsupported` is deleted, so it does not run). |
132 | 132 |
|
133 | 133 | ### Step 1.2: Replace the four UOE branches |
134 | 134 |
|
135 | | -- [ ] **Step 3: Edit `DefaultValidator.validate(...)`** |
| 135 | +- [x] **Step 3: Edit `DefaultValidator.validate(...)`** |
136 | 136 |
|
137 | 137 | Open `src/main/java/com/retailsvc/http/validate/DefaultValidator.java`. Replace these four lines: |
138 | 138 |
|
@@ -200,19 +200,19 @@ private void validateNot(Object value, Schema inner, String pointer) { |
200 | 200 | } |
201 | 201 | ``` |
202 | 202 |
|
203 | | -- [ ] **Step 4: Run the unit tests** |
| 203 | +- [x] **Step 4: Run the unit tests** |
204 | 204 |
|
205 | 205 | Run: `mvn -q test -Dtest=DefaultValidatorDispatchTest` |
206 | 206 |
|
207 | 207 | Expected: all tests in the class pass (the original 4 + the 9 new ones). |
208 | 208 |
|
209 | | -- [ ] **Step 5: Run the full unit test suite** |
| 209 | +- [x] **Step 5: Run the full unit test suite** |
210 | 210 |
|
211 | 211 | Run: `mvn -q test` |
212 | 212 |
|
213 | 213 | Expected: BUILD SUCCESS, 119 + 9 = 128 tests pass (or whatever count matches; no failures). |
214 | 214 |
|
215 | | -- [ ] **Step 6: Commit** |
| 215 | +- [x] **Step 6: Commit** |
216 | 216 |
|
217 | 217 | ```bash |
218 | 218 | git add src/main/java/com/retailsvc/http/validate/DefaultValidator.java \ |
|
241 | 241 |
|
242 | 242 | ### Step 2.1: Add failing parser tests |
243 | 243 |
|
244 | | -- [ ] **Step 1: Add tests covering the composition path** |
| 244 | +- [x] **Step 1: Add tests covering the composition path** |
245 | 245 |
|
246 | 246 | Append to `src/test/java/com/retailsvc/http/spec/schema/SchemaParserTest.java` (inside the class, before the final `}`): |
247 | 247 |
|
@@ -354,15 +354,15 @@ void aloneCombinatorStillReturnsCombinatorRecord() { |
354 | 354 | } |
355 | 355 | ``` |
356 | 356 |
|
357 | | -- [ ] **Step 2: Run the new parser tests (expect failures)** |
| 357 | +- [x] **Step 2: Run the new parser tests (expect failures)** |
358 | 358 |
|
359 | 359 | Run: `mvn -q test -Dtest=SchemaParserTest` |
360 | 360 |
|
361 | 361 | Expected: the 7 new tests fail. The composition tests fail because `parse(...)` currently returns a single combinator record (e.g. `OneOfSchema`), not an `AllOfSchema`. The `aloneCombinatorStillReturnsCombinatorRecord` test currently passes — it's a regression guard for the next step. |
362 | 362 |
|
363 | 363 | ### Step 2.2: Rewrite the parser dispatch |
364 | 364 |
|
365 | | -- [ ] **Step 3: Replace the body of `SchemaParser.parse(Map<String, Object>)`** |
| 365 | +- [x] **Step 3: Replace the body of `SchemaParser.parse(Map<String, Object>)`** |
366 | 366 |
|
367 | 367 | Open `src/main/java/com/retailsvc/http/spec/schema/SchemaParser.java`. Replace the entire `parse` method (currently lines 15–55) with: |
368 | 368 |
|
@@ -467,19 +467,19 @@ The key behaviour changes: |
467 | 467 | - The four combinator keywords are then each appended to the assertions list. `allOf` is flattened (its branches join the outer list directly), the others wrap. |
468 | 468 | - A single assertion returns unwrapped; two or more wrap in `AllOfSchema`. |
469 | 469 |
|
470 | | -- [ ] **Step 4: Run the parser tests** |
| 470 | +- [x] **Step 4: Run the parser tests** |
471 | 471 |
|
472 | 472 | Run: `mvn -q test -Dtest=SchemaParserTest` |
473 | 473 |
|
474 | 474 | Expected: all `SchemaParserTest` tests pass, including the 7 new ones. |
475 | 475 |
|
476 | | -- [ ] **Step 5: Run the full unit suite** |
| 476 | +- [x] **Step 5: Run the full unit suite** |
477 | 477 |
|
478 | 478 | Run: `mvn -q test` |
479 | 479 |
|
480 | 480 | Expected: BUILD SUCCESS, no regressions in `ContainerSchemasTest`, `PrimitiveSchemasTest`, `CombinatorScaffoldTest`, etc. |
481 | 481 |
|
482 | | -- [ ] **Step 6: Commit** |
| 482 | +- [x] **Step 6: Commit** |
483 | 483 |
|
484 | 484 | ```bash |
485 | 485 | git add src/main/java/com/retailsvc/http/spec/schema/SchemaParser.java \ |
|
515 | 515 |
|
516 | 516 | The fixture has stub `/anyOf` and `/allOf` paths with empty `post: {}`. Replace them with a real `/oneOf` route exercising a polymorphic body. |
517 | 517 |
|
518 | | -- [ ] **Step 1: Replace the stub paths in `openapi.yaml`** |
| 518 | +- [x] **Step 1: Replace the stub paths in `openapi.yaml`** |
519 | 519 |
|
520 | 520 | Open `src/test/resources/openapi.yaml`. Find the lines: |
521 | 521 |
|
@@ -560,7 +560,7 @@ Replace with: |
560 | 560 | description: OK |
561 | 561 | ``` |
562 | 562 |
|
563 | | -- [ ] **Step 2: Mirror the change in `openapi.json`** |
| 563 | +- [x] **Step 2: Mirror the change in `openapi.json`** |
564 | 564 |
|
565 | 565 | Open `src/test/resources/openapi.json`. Locate the `"/anyOf"` and `"/allOf"` keys (lines ~173 and ~178). Replace both blocks with a single `"/shapes"` entry equivalent to the YAML above. Use the existing JSON formatting (2-space indent, `application/json` media type). Worked example: |
566 | 566 |
|
@@ -604,7 +604,7 @@ Make sure the trailing comma on the previous path entry (or this one) is correct |
604 | 604 |
|
605 | 605 | ### Step 3.2: Add a test handler |
606 | 606 |
|
607 | | -- [ ] **Step 3: Create `PolymorphicHandler.java`** |
| 607 | +- [x] **Step 3: Create `PolymorphicHandler.java`** |
608 | 608 |
|
609 | 609 | Create `src/test/java/com/retailsvc/http/start/PolymorphicHandler.java`: |
610 | 610 |
|
@@ -632,7 +632,7 @@ public class PolymorphicHandler implements HttpHandler { |
632 | 632 |
|
633 | 633 | ### Step 3.3: Add the integration test |
634 | 634 |
|
635 | | -- [ ] **Step 4: Add tests to `OpenApiServerIT.java`** |
| 635 | +- [x] **Step 4: Add tests to `OpenApiServerIT.java`** |
636 | 636 |
|
637 | 637 | Open `src/test/java/com/retailsvc/http/OpenApiServerIT.java`. Add a new nested class at the bottom of the outer class (immediately before the final `}` of `OpenApiServerIT`): |
638 | 638 |
|
@@ -724,21 +724,21 @@ class Shapes { |
724 | 724 |
|
725 | 725 | The `ofString`, `BodyHandlers`, and `assertThat` imports are already present at the top of `OpenApiServerIT.java`; no new imports needed beyond `org.junit.jupiter.api.Nested` (also already present) and `java.io.IOException` (already imported). |
726 | 726 |
|
727 | | -- [ ] **Step 5: Run the integration tests** |
| 727 | +- [x] **Step 5: Run the integration tests** |
728 | 728 |
|
729 | 729 | Run: `mvn -q verify -DfailIfNoTests=false -Dtest='!*' -Dit.test=OpenApiServerIT` |
730 | 730 |
|
731 | 731 | Or simply: `mvn -q verify` |
732 | 732 |
|
733 | 733 | Expected: BUILD SUCCESS. The four new IT cases all pass. |
734 | 734 |
|
735 | | -- [ ] **Step 6: Run the full verify** |
| 735 | +- [x] **Step 6: Run the full verify** |
736 | 736 |
|
737 | 737 | Run: `mvn -q verify` |
738 | 738 |
|
739 | 739 | Expected: BUILD SUCCESS. All previous unit tests + the 9 new validator tests + the 7 new parser tests + the 4 new IT tests pass. |
740 | 740 |
|
741 | | -- [ ] **Step 7: Commit** |
| 741 | +- [x] **Step 7: Commit** |
742 | 742 |
|
743 | 743 | ```bash |
744 | 744 | git add src/test/resources/openapi.yaml src/test/resources/openapi.json \ |
|
762 | 762 |
|
763 | 763 | ## Final verification |
764 | 764 |
|
765 | | -- [ ] Run `mvn -q verify` once more. |
766 | | -- [ ] `git log --oneline master..HEAD` shows three new commits in this order: `feat: Implement combinator validation…`, `feat: Compose combinators with sibling…`, `test: Add polymorphic-body integration…`. |
767 | | -- [ ] No new files exist outside the paths listed above. |
| 765 | +- [x] Run `mvn -q verify` once more. |
| 766 | +- [x] `git log --oneline master..HEAD` shows three new commits in this order: `feat: Implement combinator validation…`, `feat: Compose combinators with sibling…`, `test: Add polymorphic-body integration…`. |
| 767 | +- [x] No new files exist outside the paths listed above. |
768 | 768 |
|
769 | 769 | ## Out of scope (do not do) |
770 | 770 |
|
|
0 commit comments