You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(migration): add ResourceDoc parity (per-version drift from Lift)
New section under "Resource-docs (separate workstream)" capturing the
state of http4s vs Lift ResourceDoc parity per version, so reviewers
can see what's pending without re-running the audit script. Covers:
- The source-of-truth principle (APIMethodsXYZ.scala = canonical) and
the verification that the commented stub files are byte-equivalent
on ResourceDoc bodies to the pre-stub live Lift code (243/243 in v6,
111/111 in v5.1).
- The three scripts in `scripts/` (audit + 2 restoration tools) and
what each is good for.
- A per-version drift table summarising 377 outstanding mismatches
across 956 endpoints.
- Detailed fix candidates for v6.0.0 (12 drifts), v5.1.0 (1 drift),
and v5.0.0 (8 drifts + 3 only-http4s) — each row tags whether the
resolution is "fix http4s to match Lift" or "document the
intentional drift at the http4s site".
- Strategy summary for the untouched versions (v1.2.1 → v4.0.0).
Copy file name to clipboardExpand all lines: LIFT_HTTP4S_MIGRATION.md
+88Lines changed: 88 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -164,6 +164,94 @@ Currently served via a raw Lift `serve { case Req(..., "openapi.yaml", ...) }` b
164
164
165
165
---
166
166
167
+
## ResourceDoc parity (per-version drift from Lift)
168
+
169
+
Separate from the resource-docs **serving** workstream above, there is a parity workstream covering the **content** of each migrated ResourceDoc declaration. The goal is for every http4s `ResourceDoc(...)` to render identically to its Lift original, so the public API docs aren't silently degraded by migration.
170
+
171
+
### Principle
172
+
173
+
**`APIMethodsXYZ.scala` (Lift) is the source of truth for migration.** The commented-out Lift ResourceDocs and endpoints inside each `APIMethodsXYZ.scala` are the canonical reference for what the http4s version should render: URL templates, verb casing, summaries, descriptions, example bodies, error lists, tags. **Do NOT edit these files to make the audit pass** — the audit compares http4s against the Lift source-of-truth. When the audit flags a diff, the resolution is either (a) update http4s to match Lift, or (b) document the difference at the http4s site as a known intentional drift (placeholder rename for middleware, upstream-driven case-class shift, etc.). Rewriting the Lift comments runs the comparison backwards and erases the historical record. (Mistakes in commits `d95c1df01` and `6154bf2cc` did this; reverted in `27f48af72`.)
174
+
175
+
**Stub fidelity verified.** Commits `810589330` (v6) and `88f46f854` (v5.1) replaced the live Lift code with commented-out stubs. Comparing each stub's uncommented ResourceDoc bodies against the pre-stub live versions: **0 field diffs across 243/243 v6 docs and 111/111 v5.1 docs**. The non-ResourceDoc deltas (imports, etc., ~16KB v6 / ~5KB v5.1) are immaterial. The stubs are an exact preservation of the original Lift ResourceDocs.
176
+
177
+
### Tooling (`scripts/`)
178
+
179
+
| Script | Role |
180
+
|---|---|
181
+
|`check_lift_http4s_resource_doc_parity.py`| Read-only audit. Parses both files, matches by `nameOf(...)` (with `.replace("a","b")` evaluation for derived names), reports per-field diffs. `--field=X` to focus, `--list-only` for endpoint-presence summary. |
182
+
|`rehydrate_resource_docs.py`| Upstream (simonredfern, `67593ea28`). Lifts positional args 7/8/9 (description, exampleRequestBody, successResponseBody) from commented Lift blocks into http4s. Has a `split-init` subcommand for JVM 64KB method-size workaround. |
183
+
|`restore_resource_doc_bodies.py`| Companion to the above. Restores any subset of (summary, description, exampleRequestBody, successResponseBody, errorResponseBodies, tags) from Lift into http4s. Surgical per-field replacement preserves layout. `--fields=X,Y` to scope, `--only=ep` to target one endpoint. |
184
+
185
+
### Current drift (audit re-run 2026-05-21 evening)
186
+
187
+
| Version | shared | mismatch | only-lift | only-http4s | Status |
### v6.0.0 — 12 specific drifts (each is a fix candidate)
204
+
205
+
These are the cases where http4s deviates from Lift. Under the source-of-truth rule, the default is to fix http4s; deliberate exceptions need to be documented at the http4s site.
206
+
207
+
| Endpoint | Field | Lift | http4s | Resolution |
208
+
|---|---|---|---|---|
209
+
|`createCounterpartyAttribute`| requestUrl |`…/counterparties/COUNTERPARTY_ID/attributes`|`…/COUNTERPARTY_ID_PARAM/…`| TBD — verify `ResourceDocMatcher` correctly handles `COUNTERPARTY_ID` as a wildcard (the literal set contains `COUNTERPARTY`, but `COUNTERPARTY_ID` is whole-segment-different). If safe, revert to Lift's name. |
210
+
|`deleteCounterpartyAttribute`| requestUrl | same | same | same as above |
211
+
|`getAllCounterpartyAttributes`| requestUrl | same | same | same as above |
212
+
|`getCounterpartyAttributeById`| requestUrl | same | same | same as above |
213
+
|`updateCounterpartyAttribute`| requestUrl | same | same | same as above |
214
+
|`createTransactionRequestCardano`| requestUrl |`…/ACCOUNT_ID/owner/transaction-request-types/CARDANO/…`|`…/ACCOUNT_ID/VIEW_ID/…/CARDANO/…`|**Functional broadening** — http4s lets any view, Lift hardcoded `owner`. Keep http4s; document at the http4s ResourceDoc site. |
215
+
|`createTransactionRequestHold`| requestUrl |`…/owner/…HOLD/…`|`…/VIEW_ID/…HOLD/…`| same as above |
216
+
|`getSystemViewById`| requestUrl |`/management/system-views/VIEW_ID`|`/management/system-views/SYS_VIEW_ID`| TBD — disambiguation rename. If `ResourceDocMatcher` handles both fine, revert. |
217
+
|`updateSystemView`| requestUrl |`/system-views/VIEW_ID`|`/system-views/UPD_VIEW_ID`| same as above |
218
+
|`removeBankReaction`| requestUrl |`…/reactions/EMOJI`|`…/reactions/EMOJI_REACTION`|`EMOJI` is NOT in `literalAllCapsSegments` (only `EMAIL`/`SMS`/`IMPLICIT` of the SCA cluster are). Rename may have been defensive; safe to revert. |
219
+
|`removeSystemReaction`| requestUrl | same | same | same as above |
220
+
|`getAccountDirectory`| successResponseBody |`FastFirehoseRoutings(bank_id, account_id)`|`AccountRoutingJsonV121(scheme, address)`|**Upstream functional change** (`9e151c524` / `9dc4c4c46` migrated the case class). Cannot revert; document. Also note: the same change broke `mvn test` (pre-existing upstream compile error in `JSONFactory6.0.0.scala:2934`). |
221
+
222
+
Also: 1 only-http4s (`createWebUiProps`) — genuinely http4s-only with no Lift counterpart. Document.
223
+
224
+
### v5.1.0 — 1 specific drift
225
+
226
+
| Endpoint | Field | Lift | http4s | Resolution |
227
+
|---|---|---|---|---|
228
+
|`revokeMyConsent`| requestVerb |`"Delete"`|`"DELETE"`| Trivial casing fix on the http4s side. |
229
+
230
+
Also:
231
+
- 1 only-lift (`createConsentImplicit`) + 1 only-http4s (`createConsent`) — Lift had `lazy val createConsentImplicit = createConsent` aliasing and registered the doc under the alias; http4s registers under the canonical name. Fix: in http4s, either rename the partial function to `createConsentImplicit` to match Lift, or register a second `nameOf(createConsentImplicit)` doc for the same handler.
232
+
- 1 only-http4s (`getBanks`) — kept in the v5.1.0 layer for metrics attribution (intentional addition; see comment at `Http4s510.scala:288`). Document.
233
+
234
+
### v5.0.0 — 8 specific drifts + 3 only-http4s
235
+
236
+
| Category | Count | Endpoints | Resolution |
237
+
|---|---|---|---|
238
+
| requestUrl placeholder rename | 1 |`createAccount` (Lift `ACCOUNT_ID` → http4s `NEW_ACCOUNT_ID` for the PUT-creates pattern) | Verify matcher behavior; may be required for `ACCOUNT_ID` literal handling. |
239
+
| errorResponseBodies — SCA val-vs-inline | 3 |`createConsentByConsentRequestIdEmail` / `Sms` / `Implicit`| http4s uses `private val createConsentByConsentRequestIdCommonErrors = List(...)` for DRY; Lift inlined the list. Either inline the val in the 3 doc registrations to match Lift verbatim, or extend the audit script to expand simple `val X = List(...)` references. |
240
+
| errorResponseBodies — system-view accuracy | 4 |`createSystemView`, `deleteSystemView`, `getSystemView`, `updateSystemView`| http4s has more accurate errors (`SystemViewNotFound`, `SystemViewCannotBePublicError`, `InvalidSystemViewFormat`). Lift had wrong/legacy errors (`BankAccountNotFound`, `$BankNotFound`, `"user does not have owner access"`). **Genuine improvement** — document at http4s site. |
241
+
242
+
Also: 3 only-http4s (`getBanks`, `getProduct`, `getProducts`) — kept in this layer for metrics attribution. Document.
243
+
244
+
### Strategy summary
245
+
246
+
For each remaining drift on a migrated version:
247
+
1.**Default**: fix http4s to match Lift verbatim. Use `restore_resource_doc_bodies.py` for field-level restoration.
248
+
2.**Documented exceptions**: where the drift is a deliberate http4s improvement or required by middleware semantics, leave the drift and add a `// Lift had X; we use Y because Z` comment at the http4s ResourceDoc site.
249
+
3.**Never**: edit `APIMethodsXYZ.scala` to make the audit pass. The Lift comments are the canonical record.
250
+
251
+
Untouched versions (v1_2_1 through v4_0_0, plus v2_1_0) need the same treatment: run `rehydrate_resource_docs.py` then `restore_resource_doc_bodies.py`, then audit and address any residual drifts at the http4s site.
252
+
253
+
---
254
+
167
255
## Auth Stack (separate workstream)
168
256
169
257
Token-generation paths — not version-file endpoints. Each `extends RestHelper` and needs to become an http4s route or middleware independently. Can run in parallel with the APIMethods migration.
0 commit comments