Skip to content

Commit 5843381

Browse files
committed
docs: revise migration plan to inside-out strategy with vertical UI slices
Replace horizontal layer-by-layer migration (8 phases) with inside-out approach (7 phases). New strategy hollows out old provider and controller from the inside by delegating to new adapter and services, then migrates UI as vertical slices per screen. Key changes: - Add compat/ translation layer for bidirectional type mapping - Phase 2: Adapter replaces provider internals - Phases 3-4: Services replace controller internals (parallelizable) - Phase 5: New controller, old becomes pure shim - Phase 6: UI migrates one screen at a time (vertical slices) - Phase 7: Cleanup and rename (merged old phases 7+8)
1 parent 6d7dab8 commit 5843381

16 files changed

Lines changed: 666 additions & 1018 deletions

app/components/UI/PredictNext/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ PredictNext/
5151
│ └── phase-5-*.md
5252
│ └── phase-6-*.md
5353
│ └── phase-7-*.md
54-
│ └── phase-8-*.md
54+
├── compat/ # Temporary translation layer (deleted in Phase 7)
55+
│ ├── mappers.ts
56+
│ ├── types.ts
57+
│ └── index.ts
5558
├── types/
5659
├── controller/
5760
├── services/
@@ -120,4 +123,4 @@ Modules are deep with slim interfaces. We use compound components similar to the
120123

121124
## Migration Status
122125

123-
This feature is being built using a strangler fig migration from the original Predict directory. Check the [migration documentation](docs/migration/README.md) for details.
126+
This feature is being built using an inside-out migration from the original Predict directory. The new adapter and services replace internals first while the old UI stays unchanged, then UI migrates as vertical slices. Check the [migration documentation](docs/migration/README.md) for details.

app/components/UI/PredictNext/docs/migration/README.md

Lines changed: 87 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,40 @@ The goal is not novelty. It is a codebase where a new team member can understand
2727

2828
## 2. Strategy
2929

30-
- Strangler fig migration: new code grows in `app/components/UI/PredictNext/`, old code shrinks in `app/components/UI/Predict/`.
31-
- Bottom-up migration: data and orchestration move first, views move last.
32-
- Every PR must be shippable, reviewable, and independently testable.
33-
- External consumers make a clean cut with explicit import switches when a new module is ready.
34-
- No shim, alias, or re-export layer between `Predict/` and `PredictNext/`.
30+
Inside-out migration: replace the internals while keeping the external interface unchanged, then replace the interface once the internals are proven.
31+
32+
- **Bottom-up through the stack.** The new adapter grows first. The old PolymarketProvider progressively delegates API calls to it. Then new services grow, and the old PredictController progressively delegates to them. By the time UI migration starts, the entire data stack is battle-tested with real production traffic.
33+
- **Translation layer as the seam.** A `compat/` module in PredictNext handles bidirectional mapping between canonical types (`PredictEvent`, `PredictMarket`, `PredictOutcome`) and legacy types (`Market`, `Outcome`, `OutcomeToken`). The data shapes are structurally identical — only the naming differs. Old code delegates down to new code, new code returns canonical types, the translation layer renames fields back to old shapes for old consumers.
34+
- **Zero UI disruption during data migration.** Phases 2 through 5 touch only the data stack. Old hooks, components, and views continue working unchanged because the old controller's public interface and state shape remain stable throughout.
35+
- **Vertical UI slices after data is proven.** Phase 6 replaces UI one screen at a time. Each slice includes new hooks, new components, and a new view for that screen. By then, the entire data layer is already in production.
36+
- **Every PR is shippable.** Users see zero behavior change during Phases 1 through 5. UI changes appear gradually during Phase 6 as screens switch one by one.
37+
- **No shim or re-export layer.** Old code delegates directly to new code via imports. New code never imports old code. The translation layer is the only bridge, and it gets deleted in Phase 7.
38+
39+
### How it works at each level
40+
41+
```
42+
Phase 2 — Adapter replaces provider internals:
43+
Old Provider method → calls New Adapter → gets canonical types → translates back to old types → returns
44+
45+
Phase 3-4 — Services replace controller internals:
46+
Old Controller method → calls New Service → gets canonical types → translates back to old state shape → publishes
47+
48+
Phase 5 — New Controller replaces old controller internals:
49+
Old Controller method → forwards to New Controller → translation at the boundary
50+
51+
Phase 6 — New UI replaces old UI:
52+
New View → New Hooks → New Controller → New Services → New Adapter
53+
(translation layer no longer needed for migrated screens)
54+
```
3555

3656
## 3. PredictNext/ Approach
3757

3858
- New architecture lives in `app/components/UI/PredictNext/`.
39-
- Existing production code in `app/components/UI/Predict/` remains the source of truth until a specific area is fully replaced.
40-
- During the transition, new code is allowed to import old implementation details where that reduces risk, especially:
41-
- `app/components/UI/Predict/providers/polymarket/PolymarketProvider.ts`
42-
- `app/components/UI/Predict/providers/polymarket/WebSocketManager.ts`
43-
- `app/components/UI/Predict/providers/polymarket/safe/*`
44-
- small pure utilities under `app/components/UI/Predict/utils/`
45-
- External consumers outside the Predict feature should switch explicitly once the relevant `PredictNext/` screen or component is ready. The main switch points are expected to include:
59+
- Old code in `app/components/UI/Predict/` progressively delegates to PredictNext internals rather than being replaced all at once.
60+
- A `PredictNext/compat/` module provides bidirectional type mappers between canonical and legacy types. This module is intentionally temporary and will be deleted in Phase 7.
61+
- During the data migration (Phases 2 through 5), old UI code is completely untouched. Old hooks subscribe to the same old controller messenger events, receive the same old state shapes, and render the same old components.
62+
- During the UI migration (Phase 6), each screen is rebuilt as a vertical slice using new hooks, components, and views that talk directly to the new controller. No screen ever mixes old and new hooks.
63+
- External consumers outside the Predict feature switch imports during Phase 6 as each screen or widget becomes available in PredictNext. The main switch points are expected to include:
4664
- `app/core/Engine/controllers/predict-controller/index.ts`
4765
- `app/core/Engine/messengers/predict-controller-messenger/index.ts`
4866
- `app/core/Engine/types.ts`
@@ -66,59 +84,64 @@ The goal is not novelty. It is a codebase where a new team member can understand
6684

6785
## 4. Phase Summary
6886

69-
| Phase | Name | Goal | Est. PRs | Dependencies |
70-
| ----- | ------------------- | ------------------------------------------------------------ | -------- | ------------ |
71-
| 1 | Foundation | Types, glossary, adapter interface, PredictError | 2-3 | None |
72-
| 2 | Data Services | MarketDataService, PortfolioService, messenger registration | 3-4 | Phase 1 |
73-
| 3 | Imperative Services | Trading, Transaction, LiveData, Analytics service extraction | 4-5 | Phase 1 |
74-
| 4 | Controller | Thin PredictController orchestrator | 1-2 | Phases 2, 3 |
75-
| 5 | Hooks | Consolidate 37 hooks into 7 deep hooks | 3-4 | Phase 4 |
76-
| 6 | Components | Build Tier 1 primitives and Tier 2 widgets | 5-7 | Phase 1 |
77-
| 7 | Views | Screen migration, route switches, component view tests | 4-6 | Phases 5, 6 |
78-
| 8 | Cleanup | Delete old feature, rename folder, remove migration seams | 1-2 | Phase 7 |
87+
| Phase | Name | Goal | Est. PRs | Dependencies |
88+
| ----- | ------------------------------ | ------------------------------------------------------------------------ | -------- | ------------ |
89+
| 1 | Foundation | Types, adapter interface, error model, translation layer | 2-3 | None |
90+
| 2 | Adapter & Provider Migration | New PolymarketAdapter, old provider delegates API calls to it | 3-5 | Phase 1 |
91+
| 3 | Read Services | MarketDataService, PortfolioService, old controller delegates reads | 3-4 | Phase 2 |
92+
| 4 | Write Services | TradingService, TransactionService, LiveDataService, AnalyticsService | 4-5 | Phase 2 |
93+
| 5 | New Controller | New PredictController, old controller becomes pure translation shim | 1-2 | Phases 3, 4 |
94+
| 6 | UI Migration (Vertical Slices) | Hooks + components + views, one screen at a time | 8-12 | Phase 5 |
95+
| 7 | Cleanup | Delete old code, rename PredictNext to Predict, remove translation layer | 1-2 | Phase 6 |
7996

80-
Note: Phases 2-3 and Phase 6 can run in parallel because service extraction depends on the canonical domain model, while component construction only needs the new types and ubiquitous language.
97+
Note: Phases 3 and 4 can run in parallel because read services and write services are independent. Both depend on the adapter from Phase 2.
8198

8299
## 5. Parallel Work Streams
83100

84-
### Stream A: Data and orchestration
101+
### Stream A: Read path
85102

86-
`Phase 1 -> Phase 2 -> Phase 3 -> Phase 4 -> Phase 5`
103+
`Phase 1 Phase 2 Phase 3`
87104

88105
- Phase 1 defines the vocabulary and contracts.
89-
- Phase 2 builds read/data services.
90-
- Phase 3 extracts write and live-update services.
91-
- Phase 4 composes those services behind a new controller.
92-
- Phase 5 gives views a stable React interface.
106+
- Phase 2 builds the adapter and hollows out the old provider.
107+
- Phase 3 builds read services and hollows out the old controller's read methods.
93108

94-
### Stream B: UI primitives and widgets
109+
### Stream B: Write path
95110

96-
`Phase 1 -> Phase 6`
111+
`Phase 1 Phase 2 → Phase 4`
97112

98-
- Phase 6 can start as soon as the `PredictEvent`, `PredictMarket`, `PredictOutcome`, `PredictPosition`, and `ActivityItem` types are stable.
99-
- This stream should use mock data shaped from `PredictNext/types/index.ts`, not direct reads from controller state.
113+
- Phase 4 can start as soon as the adapter from Phase 2 is stable.
114+
- Write services (trading, transactions, live data, analytics) are independent of read services.
100115

101116
### Merge point
102117

103-
`Phase 7`
118+
`Phase 5`
119+
120+
- The new controller composes all six services from both streams.
121+
- The old controller becomes a pure translation shim.
122+
123+
### UI stream
104124

105-
- Views need both the new hooks from Stream A and the new primitives/widgets from Stream B.
125+
`Phase 5 → Phase 6`
126+
127+
- UI migration starts only after the full data stack is proven in production.
128+
- Within Phase 6, different screens can be migrated in parallel by different developers.
106129

107130
### Final stream
108131

109-
`Phase 8`
132+
`Phase 7`
110133

111-
- Cleanup only starts after every routed screen and every external embed point has switched to `PredictNext/`.
134+
- Cleanup starts after every routed screen and every external embed point has switched to PredictNext.
112135

113136
## 6. Risk Mitigation
114137

115-
- Each phase has explicit acceptance criteria and should not proceed on partial completion.
116-
- Old code remains functional throughout the migration; revertability is preserved until the final rename.
117-
- `PredictNext/` may delegate to old provider/controller logic early in the migration to reduce blast radius.
118-
- Route-by-route migration prevents a big-bang UI rewrite.
119-
- Feature flags can gate new `PredictNext/views/*` route registration if rollout needs to be staged.
120-
- Rollback strategy is simple for Phases 1-7: revert `PredictNext/` PRs and keep old `Predict/` active.
121-
- Service extraction should favor adapter seams and deterministic unit tests before production route switches.
138+
- **Zero UI disruption during data migration.** Phases 2 through 5 do not touch any view, hook, or component file in old code. If a service extraction causes a regression, the failure is isolated to the data path and the old code can stop delegating with a one-line revert.
139+
- **Translation layer is structurally trivial.** The canonical types and legacy types are isomorphic — same nesting, different names. The translation layer is field renames, not structural transformation, so the risk of data loss is minimal.
140+
- **Incremental provider delegation.** Each adapter method is wired one at a time in the old provider. If one method causes issues, only that method reverts. The rest of the provider continues delegating.
141+
- **Incremental controller delegation.** Same pattern: each controller method delegates to new services one at a time. Partial delegation is a stable intermediate state.
142+
- **Feature work goes in old code.** During Phases 2 through 5, all new features are built in old Predict code. They automatically benefit from new internals because the old code delegates underneath. No confusion about where new code goes.
143+
- **UI migration is per-screen.** Phase 6 migrates one screen at a time. Each screen switch is independently revertable. If the event details screen has issues, the event feed screen is unaffected.
144+
- **Rollback at any phase.** Phases 1 through 5: stop delegating and revert PredictNext PRs. Phase 6: revert route switch for the affected screen. Phase 7: do not start until all screens are stable.
122145

123146
## 7. Definition of Done
124147

@@ -127,6 +150,7 @@ Note: Phases 2-3 and Phase 6 can run in parallel because service extraction depe
127150
- All component view tests for Predict pass against the migrated views.
128151
- Engine registration points instantiate the new Predict controller.
129152
- No runtime imports from old `Predict/` remain.
153+
- Translation layer (`PredictNext/compat/`) is deleted.
130154
- `UBIQUITOUS_LANGUAGE.md` is complete and reflected in code symbols.
131155
- `PredictNext/README.md` and `PredictNext/docs/*` describe the shipped architecture rather than the transitional one.
132156

@@ -140,7 +164,7 @@ The migration is not a file move only; it also corrects the domain model:
140164
| `Outcome` | `Market` | Old outcome collections frequently map to binary markets |
141165
| `OutcomeToken` | `Outcome` | Tradeable yes/no token becomes the new outcome concept |
142166

143-
These conversions must be applied consistently in:
167+
These conversions are handled by the `PredictNext/compat/` translation layer during Phases 2 through 5. They must be applied consistently in:
144168

145169
- `PredictNext/types/index.ts`
146170
- service method names
@@ -152,19 +176,25 @@ These conversions must be applied consistently in:
152176

153177
## 9. Recommended PR Order
154178

155-
1. Phase 1 contracts and error model
156-
2. Phase 2 read/data services + registration
157-
3. Phase 3 imperative services
158-
4. Phase 4 thin controller + Engine switch
159-
5. Phase 5 new hooks and hook consumers behind non-routed test surfaces
160-
6. Phase 6 primitives/widgets in parallel
161-
7. Phase 7 screen-by-screen route and consumer switches
162-
8. Phase 8 deletion, rename, and final import cleanup
179+
1. Phase 1 contracts, error model, and translation layer
180+
2. Phase 2 adapter implementation and initial provider delegation
181+
3. Phase 2 continued provider delegation (method by method, as many PRs as needed)
182+
4. Phase 3 read services plus old controller read delegation
183+
5. Phase 4 write services plus old controller write delegation (can parallel with 4)
184+
6. Phase 5 new controller plus old controller becomes shim
185+
7. Phase 6 vertical slice: event feed (home screen)
186+
8. Phase 6 vertical slice: event details
187+
9. Phase 6 vertical slice: portfolio sections
188+
10. Phase 6 vertical slice: order flow
189+
11. Phase 6 vertical slice: modals and remaining screens
190+
12. Phase 6 external consumer import switches
191+
13. Phase 7 deletion, rename, and final import cleanup
163192

164193
## 10. Review Expectations
165194

166-
- Review contracts first: `types/`, `adapters/types.ts`, `errors/`.
167-
- Review extraction PRs by bounded context, not by file count.
168-
- Keep route changes, service extraction, and large visual rewrites in separate PRs whenever possible.
169-
- Prefer explicit temporary delegation comments over hidden coupling.
195+
- Review contracts first: `types/`, `adapters/types.ts`, `errors/`, `compat/`.
196+
- Review delegation PRs by verifying that old behavior is preserved: same state shape, same messenger events, same hook return values.
197+
- Review service extraction PRs by bounded context, not by file count.
198+
- Review UI vertical slices as complete screen replacements: hooks, components, view, and component view tests in one reviewable unit.
199+
- Prefer explicit temporary delegation comments in old code over hidden coupling.
170200
- Do not merge a phase PR without the acceptance criteria from its phase document being met.

0 commit comments

Comments
 (0)