Skip to content

Migration#2810

Merged
simonredfern merged 9 commits into
OpenBankProject:developfrom
constantine2nd:develop
May 25, 2026
Merged

Migration#2810
simonredfern merged 9 commits into
OpenBankProject:developfrom
constantine2nd:develop

Conversation

@constantine2nd
Copy link
Copy Markdown
Contributor

No description provided.

…" / "counter party")

Per Simon's review comment on the new PR:

  "counter party from the perpestive" → "counterparty from the perspective"

Two occurrences in Http4s121.scala:
  - addCounterpartyMoreInfo  (POST .../metadata/more_info)
  - updateCounterpartyMoreInfo  (PUT .../metadata/more_info)

Both were restored verbatim from APIMethods121.scala in 813f7a4, which
also has the typos. Per the source-of-truth rule, the Lift file is not
modified — the typo fix lives on the http4s side with a comment marking
the intentional drift.
…geTraffic

Data-driven prioritisation for the "remove Lift Web" milestone. Every
request that reaches `Http4sLiftWebBridge.dispatch` is now tallied in
an in-memory map of (method × path-bucket) → hit count.

- First hit of a new bucket is logged at INFO:
    [BRIDGE-AUDIT] first hit: METHOD /path/bucket   (original path: ...)
  Subsequent hits only increment the AtomicLong (no per-request log
  spam).

- New admin route `GET /admin/lift-bridge-traffic` returns the full
  snapshot as JSON, sorted by hit count desc. Wired into
  Http4sApp.baseServices ahead of the per-version routes so the admin
  path can't be shadowed by a Lift fallback.

- `POST /admin/lift-bridge-traffic/reset` clears the tally (handy
  before a baseline run).

Path-bucket normalisation collapses opaque IDs so the map stays
small: UUIDs → {uuid}, all-digits → {n}, any segment with a `.` (and
not an API-version string) → {id}, ≥12-char mixed alphanumeric → {id}.
API-version strings (v6.0.0, v1_2_1) are kept verbatim. Unit-tested
in Http4sLiftBridgeTrafficTest (8 cases).

The migration doc gains a "Bridge-traffic audit" subsection under
"Migration leftovers" with an operator playbook for confirming
bridge-readiness for retirement.

Operator playbook:
  1. POST /admin/lift-bridge-traffic/reset on a representative instance.
  2. Run a normal traffic window (e.g. 24h + daily/weekly jobs).
  3. GET /admin/lift-bridge-traffic — every bucket left is either a
     documented leftover (OIDC callback, etc.) or a new migration
     target.

When the snapshot is empty for a full traffic window the bridge can
be retired.
…it real work from 404 probes

First-pass audit (commit 28dafdc) couldn't tell apart "Lift actually
handled this request" from "Lift returned 404 because nothing matched"
— both bumped the same counter. Shard 1's first real CI snapshot
caught a v4.0.0 `DELETE /banks/{id}/accounts` bucket that turned out
to be `DeleteBankCascadeTest` deliberately probing for 404 after a
cascade delete; not a missing migration.

Extend the audit to key on `(method, bucket, status)`:

- `observe(method, path, status)` instead of `observe(method, path)`.
  Called from `dispatch` AFTER the response is built (or 500 in the
  error path) so the actual outcome is captured.

- First-hit INFO log now includes the status:
    [BRIDGE-AUDIT] first hit: METHOD /path/bucket STATUS   (original path: ...)

- `GET /admin/lift-bridge-traffic` now returns two groups:
    "real_work" — non-404 entries. Each one is a (method, URL pattern,
                  status) that's actually doing something on Lift.
                  These are the migration targets.
    "not_found" — 404 entries. Test probes, stale callers, dead links.
                  Informational, not blocking bridge removal.
  Each group is sorted by hit count desc. Summary block carries the
  unique-bucket and total-hit counts per group.

- Unit tests gain a case that the same (method, bucket) keys
  separately when the status differs — 200 and 404 don't collide.

Migration doc updated with the new JSON shape, an explicit
"empty real_work == ready to retire" rule, and the first concrete
audit findings from shard 1 (20 dynamic-entity/endpoint buckets
= a real workstream; 2 v4.0.0 buckets = test-probe 404 noise).
…refix

Drop the `prefix == "v6.0.0"` guard that Http4sResourceDocs inherited
from the original Lift setup (only ResourceDocs600 registered the
OpenAPI 3.1 routes). The handlers depend solely on the requested-API-
version path segment (`requestedApiVersionString`), not on the URL
prefix — `implForPrefix(prefix)` already falls back to `ImplDefault`
for non-v6 prefixes, and `isVersion4OrHigher` is hardcoded `true`
inside the handlers because the OpenAPI converter always consumes the
v4-shape input. The prefix guard added no value, just surprised
callers hitting `/obp/v5.1.0/resource-docs/v5.1.0/openapi` with a Lift
404 fall-through.

After this change:

  GET /obp/{ANY_PREFIX}/resource-docs/{API_VERSION}/openapi      → 200 JSON
  GET /obp/{ANY_PREFIX}/resource-docs/{API_VERSION}/openapi.yaml → 200 YAML

Tests: SwaggerDocsTest gains two scenarios that hit /openapi and
/openapi.yaml under the v5.1.0 URL prefix and assert 200. The existing
v6.0.0-prefix scenarios continue to pass (12 total now).

Step #1 from the as-is overview's to-do list. Closes a small but
real bridge fall-through that the audit endpoint had surfaced as a
candidate; reduces the surface area Lift still has to handle.
…eftovers table

Both `getMessageDocsSwagger` and `getObpConnectorLoopback` are listed
in the per-version-leftovers table as if they still hit the Lift
bridge, but they don't. Audit confirms zero bridge hits for either.

- `getObpConnectorLoopback` — native http4s route in `Http4s310.scala`
  (~line 4875) that returns 400 NotImplemented, mirroring Lift's
  deprecated-stub behaviour. No bridge dispatch.

- `getMessageDocsSwagger` — real handler is `Http4sResourceDocs.handleGetMessageDocsSwagger`,
  matched by the wildcard `/obp/*/message-docs/{CONNECTOR}/swagger2.0`
  route before any per-version service. `Http4s310.scala` keeps a
  one-line `HttpRoutes.empty` stub + a `ResourceDoc` entry so
  `nameOf(getMessageDocsSwagger)` compiles in test files and the
  `FrozenClassTest` STABLE-API-surface guard keeps passing.

The doc table previously said "kept until the bridge-removal PR
retires it" / "Both retire together in the bridge-removal PR" —
which was the original plan, but the work has actually happened in
the meantime. Update the rows to reflect reality + cross out the
matching item in the Resource-docs workstream steps and the
bridge-leftovers summary.

No code change. Both stubs remain deletable in the future
bridge-removal PR alongside the frozen-snapshot refresh.
@sonarqubecloud
Copy link
Copy Markdown

@simonredfern simonredfern merged commit 24b22ca into OpenBankProject:develop May 25, 2026
7 checks passed
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.

2 participants