Skip to content

refactor: remove retired API standards and superseded Lift stubs - #2904

Open
hongwei1 wants to merge 31 commits into
OpenBankProject:developfrom
hongwei1:chore/remove-retired-lift-standards
Open

refactor: remove retired API standards and superseded Lift stubs#2904
hongwei1 wants to merge 31 commits into
OpenBankProject:developfrom
hongwei1:chore/remove-retired-lift-standards

Conversation

@hongwei1

@hongwei1 hongwei1 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Removes the dead Scala source left behind by the Lift-to-http4s migration, in three
stages: the retired standards and orphan files, the 12 APIMethods*.scala shims, and
finally the 12 OBPAPI*.scala aggregator objects. Net removal — nothing is moved to an
archive directory, and the historical ResourceDoc documentation that lived in those
files is preserved as a digest-verified JSON baseline rather than lost.

BASE_SHA: a98ba9847d843c6717f7f7aaa6c5cf6488819c9a (origin/develop).
343 files changed, ~103,000 lines removed.


Stage 1 — retired standards and orphans (~41,000 lines)

Five retired API standards (fully commented out and taken off the routing bridge in
#2814 / commit d19af2b92, confirmed zero live consumers): code/api/BahrainOBF/v1_0_0/
(22 files), code/api/AUOpenBanking/v1_0_0/ (11), code/api/Polish/v2_1_1_1/ (5),
code/api/STET/v1_4/ (5), code/api/MxOF/ (4, includes CNBV9_1_0_0.scala).

Superseded Lift stubs, already fully commented out, with routes now served natively by
the corresponding Http4sXXX objects: code/api/UKOpenBanking/v3_1_0/ (20 *Api.scala,
replaced by Http4sUKOBv310*), code/api/UKOpenBanking/v2_0_0/APIMethods_UKOpenBanking_200.scala
(replaced by Http4sUKOBv200), code/api/berlin/group/v1_3/ (5 *Api.scala, replaced by
Http4sBGv13*).

The aggregator objects (OBP_UKOpenBanking_310, OBP_UKOpenBanking_200,
OBP_BERLIN_GROUP_1_3) are kept — still needed for ScannedApis classpath registration —
but their trailing blocks of commented-out Lift dispatch are stripped. Same for
ResourceDocs140.scala.

Zero-consumer orphans: code/api/v1_2/OBPAPI1.2.scala (the sibling JSONFactory1.2.scala
is untouched — still live), code/database/authorisation/, code/yearlycustomercharges/,
code/api/openidconnect.scala, code/opentok/OpenTokUtil.scala,
code/api/sandbox/SandboxApiCalls.scala, code/api/v3_0_0/custom/APIMethodsCustom300.scala,
two fully commented-out test files, one zero-byte test file, and scripts/OpenAPI31Exporter.scala
(a standalone script with no consumers that parsed Lift ResourceDoc text with an
anchor-less regex, silently broken since APIMethods600.scala went fully commented-out).


Stage 2 — the 12 APIMethods*.scala shims (~60,600 lines)

These had shrunk to thin runtime shims plus commented-out Lift ResourceDoc text. Before
deleting them:

Two real endpoint gaps fixed (Http4s400.scala). getAllJsonSchemaValidations and
getAllAuthenticationTypeValidations each serve a /management/... (authenticated) and an
/endpoints/... (public) route, but the public variant had no ResourceDoc of its own — it
piggy-backed on the management route's doc, which wrongly implied auth was required, and the
two props that were supposed to gate it (read_json_schema_validation_requires_role,
read_authentication_type_validation_requires_role) had never been wired into the http4s
path at all, leaving /endpoints/... unconditionally public. Recovered the original Lift
design from the doomed file's own history and restored it: a dedicated public ResourceDoc
per endpoint with a prop-conditional error list. Since ResourceDocMiddleware.needsAuthentication
reads this from the matched doc, no handler-body branching was needed.

Two new test classes (JsonSchemaValidationPublicPropTrueTest,
AuthenticationTypeValidationPublicPropTrueTest) cover the prop=true branch. They are tagged
PropGatedPublicEndpoint and run in their own JVM, because the prop's effect on the doc's
error list is fixed at object-init time — one JVM can only ever observe one branch. Wired into
pom.xml (via a test.tagsToExclude property, so the exclusion is actually overridable from
the command line), run_tests_parallel.sh, and both CI workflows as a new shard 10.

JSON baseline replaces the commented-out Lift source (scripts/resource_doc_baseline/).
One file per API version, 964 endpoints, each field stored as the literal unevaluated Scala
source snippet it always was — rehydrate_resource_docs.py / restore_resource_doc_bodies.py
splice that text verbatim into live .scala files, so it has to stay text. export_and_verify.py
performed the one-time export and proved it lossless: extract from .scala, write JSON, read it
back, and assert the digest sets are identical — same keys, same values, not merely the same
count — before writing digest_manifest.json. That gate is what made deleting the files safe.

Parity audit rewritten, allowlist added. check_lift_http4s_resource_doc_parity.py now
reads the Lift side from the JSON baseline (the http4s side is unchanged, still live .scala).
parity_allowlist.json is new: every previously-unreviewed difference is now either a fresh
failure or a digest-bound, reviewed entry. All 154 current differences (2 rename pairs, 4
Lift-only, 13 http4s-only, 136 field mismatches) were checked against the handler code on both
sides rather than just the doc text. Every one is an intentional http4s improvement — including
a few worth flagging: a role gate added to signal-channel deletion, input validation added to
signal messages, and the password-reset endpoint no longer echoing the reset URL in its response.
None were regressions.

A pre-existing tooling bug found along the way. rehydrate_resource_docs.py and
restore_resource_doc_bodies.py both hardcoded ResourceDoc constructor argument positions
from the pre-teardown signature (a leading partialFunction parameter that no longer exists),
so both silently matched zero endpoints against any current file — verified before the fix
(0 matches everywhere) and after (e.g. 243/244 on v6.0.0). scripts/count_v7_endpoints.py had
the identical bug, reporting 0 endpoints instead of 852. Fixed by detecting which signature a
call uses, reusing the logic the parity script already had rather than adding a third
hardcoded guess.


Stage 3 — the 12 OBPAPI*.scala aggregators (787 lines)

Http4sResourceDocAggregation already computed every version's catalog; these objects were
its last remaining callers, plus a set of re-export vals. Moved out in order:

  • The three excludeEndpoints lists into Http4sResourceDocAggregation (nameOf is a
    compile-time macro over the member name, so sourcing it from Http4sNNN.ImplementationsX
    yields identical strings).
  • version / versionStatus for the v5.0.0 and v5.1.0 root endpoints — both Http4sNNN
    objects already declared their own versionStatus with matching values, so the
    /root payload is byte-identical.
  • ~160 test references. The mapping keys off the Implementations number rather than the
    OBPAPI one: OBPAPI3_0_0.Implementations2_2_0 really is Http4s220.Implementations2_2_0.
  • FrozenClassUtil's version list. It recovered this by scanning the classpath for
    VersionedOBPApis implementors, which in practice meant exactly these objects — so deleting
    them would have emptied it. Worth noting how that would have failed: only the first of the
    five frozen-contract scenarios asserts against an empty list; the other four iterate the
    intersection and pass vacuously. Regenerating the fixture to "fix" the one red test would
    have written an empty fixture and disabled all five guards with a green build. Instead the
    enumeration is now explicit on Http4sResourceDocAggregation, reading each version's status
    from its Http4sNNN so there is still one declaration per version. The fixtures were produced
    by the old scan and still match byte for byte, which is what makes the two paths equivalent.
  • VersionedOBPApis itself is deleted: with that scan gone it had no consumers, and its only
    remaining implementors were the two dynamic aggregators, whose members are read directly.

Two latent defects surfaced while doing this, both of which the deleted objects had been
masking, and both fixed here:

  • Http4sResourceDocAggregation.v121 was the one catalog that did not force its own
    Implementations object, on the documented grounds that Http4sApp startup always did.
    The OBPAPI* objects were also doing it from their static initializers, so a caller that
    reads a catalog without booting a server (SwaggerPathOrderAndArrayBodyTest is a plain
    FlatSpec) lost that cover. Since every later catalog snapshots v121 into a fresh buffer,
    an unpopulated one would drop all 70 v1.2.1 docs from the entire chain for the life of the JVM.
  • scripts/count_v7_endpoints.py read excludeEndpoints per-version from the OBPAPI* files.
    With them gone it found nothing and, by design, treated "absent" as "empty" — so it silently
    stopped filtering and reported 871 reachable endpoints instead of 852. It now reads the
    suffixed names from their new home; the count is 852 again, with 6/8/14 excludes for
    v4.0.0/v5.1.0/v6.0.0.

Not touched

  • obp-commons (published artifact for sibling repos)
  • code/api/v1_2/JSONFactory1.2.scala, code/api/berlin/group/v1_3/BgSpecValidation.scala
    live code in the same packages as deleted files
  • The two dynamic aggregators (OBPAPIDynamicEntity, OBPAPIDynamicEndpoint), beyond dropping
    the now-empty trait

Testing

  • mvn -o test-compile: clean, checked after every commit.
  • export_and_verify.py --write: digest gate passed (9,288 field digests matching byte for
    byte across all 12 versions) before any .scala file was touched; --check-only passes
    before and after the deletion commit.
  • check_lift_http4s_resource_doc_parity.py: exits 0, zero stale allowlist entries. Confirmed
    the JSON-reading path produces identical shared/mismatch/only-* counts (958/115/6/15) to the
    original .scala-reading path before any allowlist entries existed.
  • count_v7_endpoints.py: 852 reachable endpoints, unchanged across stages 2 and 3.
  • Frozen-contract fixtures: FrozenClassTest + FrozenMetaDataTextTest pass against fixtures
    generated by the old reflection path, with the aggregators still present and after their
    removal.
  • Live-instance smoke test (bootstrap.http4s.Http4sServer, isolated port): with the two props
    at their default, /obp/v4.0.0/endpoints/json-schema-validations and
    /endpoints/authentication-type-validations return 200 anonymously while their
    /management/... twins still 401; with both props forced true, the public routes return 401.
    Root and the v4.0.0 resource-docs listing responded normally throughout.
  • grep for APIMethods(121|130|...|600) and OBPAPI(1_2_1|...|6_0_0) across *.scala: zero hits.
  • Full run_tests_parallel.sh: all 4 shards plus the dedicated PropGatedPublicEndpoint step green — 3688 tests, 0 failures, 0 errors, 16 skipped/canceled

The ApiVersionUtilsTest failure noted in this PR's earlier description ("20 was not equal to
21") was pre-existing and is fixed here: test.default.props is gitignored, so local copies
drift from what CI's "Setup props" step injects; without berlin_group_v1_3_alias_path,
OBP_BERLIN_GROUP_1_3_Alias reports an empty ScannedApiVersion and is filtered out of
versionMapScannedApis, giving 20 versions instead of 21. run_tests_parallel.sh now injects
OBP_BERLIN_GROUP_V1_3_ALIAS_PATH, mirroring the three other CI-vs-local props gaps that
function already works around.

…lish, STET, MxOF)

These five standards were commented out of the Lift bridge in PR OpenBankProject#2814
(commit d19af2b) and have had no live route since. The http4s
migration never targeted them and nothing in the codebase references
their objects; delete the dead source outright instead of keeping it
as commented-out text.
The 20 Lift *Api.scala files under UKOpenBanking/v3_1_0 have been
fully replaced by the corresponding Http4sUKOBv310* objects, as
documented in OBP_UKOpenBanking_310's aggregator comment. Their
routes and resource docs are served natively; nothing else in the
codebase references these types.
APIMethods_UKOpenBanking_200 is fully commented out; its routes are
served natively by Http4sUKOBv200, gated in Http4sApp's baseServices
chain. Nothing references the Lift object.
The 5 Lift *Api.scala files under berlin/group/v1_3 have been fully
replaced by the corresponding Http4sBGv13* objects. OBP_BERLIN_GROUP_1_3's
aggregator comment documents the migration and confirms routes are
served by Http4sBGv13.wrappedRoutes; BgSpecValidation.scala (live
validation logic) is untouched.
Superseded by v1_2_1/OBPAPI1.2.1.scala. JSONFactory1.2.scala in the
same package stays untouched — it defines AccountJSON/AccountsJSON/
ErrorMessage, which are still imported by APIUtil.scala and
API2_2_0Test.scala.
Both packages are fully commented out (Authorisation/AuthorisationProvider/
MappedAuthorisationProvider and YearlyCharge/MappedYearlyChargeProvider),
with zero live consumers across the codebase.
Entire file is dead Lift-era source with no active declarations.
EthereumConnector_vSept2025Test.scala and API3_0_0Test.scala are
entirely commented out and exercise nothing.
- OpenTokUtil.scala and SandboxApiCalls.scala: fully commented out.
- APIMethodsCustom300.scala: empty trait for a retired endpoint whose
  only route was hard-coded to null and whose resourceDocs buffer was
  always empty; no consumer references it anywhere in the codebase.
- MockedJune2017Connector.scala: empty file.
Zero consumers anywhere in the repo (not wired into any CI workflow,
build step, or documentation), last touched 2026-01-20. It parsed
Lift ResourceDoc text out of APIMethods600.scala with an
anchor-less regex that matches inside comment lines, so it has been
silently broken since that file's contents went fully commented-out.
Not part of the Maven build (a standalone `scala` script, not
referenced from any pom.xml). A replacement exporter, if needed,
should read the current http4s resource-doc/OpenAPI output instead of
depending on retired Lift source text.
ResourceDocs140.scala and the UK Open Banking v2.0.0/v3.1.0 and Berlin
Group v1.3 aggregator objects each carried a trailing block of
commented-out Lift dispatch code below their still-active http4s
delegation. Removed the dead blocks; kept the explanatory comment
that documents why each object is retained and where its routes are
actually served.
test.default.props is gitignored and each developer maintains their
own local copy, so it can silently drift from what CI's "Setup props"
step injects. Without berlin_group_v1_3_alias_path set,
OBP_BERLIN_GROUP_1_3_Alias reports an empty ScannedApiVersion and
ScannedApis.isAddressable filters it out of versionMapScannedApis
entirely, so ApiVersionUtilsTest's `versions.length shouldBe(21)`
sees only 20 registered API versions locally while CI (which does set
the prop) sees 21.

Inject OBP_BERLIN_GROUP_V1_3_ALIAS_PATH as an env var override,
mirroring how run_tests_parallel.sh already closes the same kind of
gap for mail.test.mode, dynamic_code_sandbox_permissions and
allow_user_generated_scala_code, rather than editing the developer's
local props file.

Confirmed by reproducing the failure on a clean origin/develop
checkout with the var unset, then reproducing a pass with it set.
Http4s400's getAllJsonSchemaValidations and getAllAuthenticationTypeValidations
each serve two GET routes: /management/... (authenticated) and
/endpoints/... (a public variant). The public variant was live but had no
ResourceDoc of its own, so it silently piggy-backed on the management
route's doc -- which lists $AuthenticatedUserIsRequired even though the
public route enforces no such thing. The two props Lift used to gate this
(read_json_schema_validation_requires_role,
read_authentication_type_validation_requires_role) were fully dead: never
read anywhere in the http4s port.

Recovered the original Lift ResourceDoc text for both public variants (from
the now-deleted APIMethods400.scala's commented-out history) and added them
as dedicated ResourceDoc entries with roles=None and an error list that
conditionally includes $AuthenticatedUserIsRequired based on the prop.
ResourceDocMiddleware.needsAuthentication reads this per-request from the
matched doc, so no handler-body branching is needed -- the existing
executeAndRespond handler already works for both prop states, and the
middleware enforces auth before it ever runs when the prop is true.

Also corrected a stale "no Lift counterpart" comment on the existing
getAllAuthenticationTypeValidationsPublic alias (a commented-out Lift
counterpart does exist) and added the equivalent
getAllJsonSchemaValidationsPublic alias, which was missing.

Because the prop's effect on a ResourceDoc's error list is computed once at
object-init time, a single running JVM only ever observes one value of it.
Added two test classes tagged PropGatedPublicEndpoint that boot their own
JVM with the props forced true (JsonSchemaValidationPublicPropTrueTest,
AuthenticationTypeValidationPublicPropTrueTest), verifying anonymous 401 /
authenticated 200. Every ordinary shard continues to exercise the default
(false) branch via the existing JsonSchemaValidationTest /
AuthenticationTypeValidationTest anonymous-200 scenarios.

Wired PropGatedPublicEndpoint into pom.xml's default tagsToExclude (via a
new test.tagsToExclude property, since a plain literal there can't be
overridden by a command-line -D), run_tests_parallel.sh (a dedicated
sequential step after the main shards), and both CI workflows (a new shard
10, mirroring the existing per-shard override pattern).
…line

The 12 APIMethodsXYZ.scala files (about to be deleted in a follow-up
commit) had shrunk to thin runtime shims plus ~60,000 lines of
commented-out original Lift ResourceDoc text, kept only so
check_lift_http4s_resource_doc_parity.py could audit http4s against it.
Exported that text into scripts/resource_doc_baseline/ instead, one
JSON file per API version, each field stored as the literal,
unevaluated Scala source snippet it always was (not a parsed value) --
rehydrate_resource_docs.py and restore_resource_doc_bodies.py splice
this text verbatim into a live .scala file, so the JSON has to stay
reproducible Scala source text, not an evaluated representation.

export_and_verify.py did the one-time export: extract every field from
the live .scala source, write the JSON, read it back, and assert the
two digest sets are identical -- same keys, same values, not just the
same count -- before writing digest_manifest.json. That gate is what
lets the .scala files be deleted with confidence nothing was lost in
translation; --check-only re-verifies it any time after.

check_lift_http4s_resource_doc_parity.py now reads the Lift side from
this JSON baseline (the http4s side is untouched -- still live .scala).
Added an allowlist mechanism (parity_allowlist.json) since none
existed before: every difference between the two sides is either a new
failure or a reviewed, digest-bound entry -- rename pairs, endpoints
that only exist on one side, or individual field differences -- bound
to the normalized value's digest so reformatting is tolerated but any
real content change re-triggers a failure rather than being silently
suppressed forever. allowlist_helper.py computes those digests from
live data instead of hand-typing sha256 hashes.

Populated the allowlist after reviewing all 154 current differences
(2 rename pairs, 4 Lift-only, 13 http4s-only, 136 field mismatches):
every one is an intentional http4s improvement over the Lift original
(a fixed verb-casing bug, a corrected stale description, a clarified
URL template variable, a documented new field) -- verified against the
actual handler code on both sides, not just the doc text, with a
handful of security-relevant fixes (a role gate added to signal-channel
deletion, input validation added to signal messages, the password-reset
endpoint no longer echoing the reset URL in its response) worth a
specific mention for anyone auditing this later. None were regressions.
check_lift_http4s_resource_doc_parity.py now exits 0.

Also fixed a real, pre-existing bug in rehydrate_resource_docs.py and
restore_resource_doc_bodies.py while updating them to read the JSON
baseline: both hardcoded ResourceDoc constructor argument positions
assuming the pre-Lift-teardown signature (a leading partialFunction
parameter that no longer exists), so both silently matched zero
endpoints against any current-signature Http4sXYZ.scala file. Fixed by
detecting which signature a given call uses, the same way
check_lift_http4s_resource_doc_parity.py already did, instead of a
second hardcoked guess that had drifted out of sync with it.
…letion

CLAUDE.md's migration rule pointed at the 12 APIMethodsXYZ.scala files
as the source of truth for what http4s should match. Repointed it at
scripts/resource_doc_baseline/ (see the previous commit) and the
allowlist workflow for documenting reviewed differences, before those
.scala files are deleted in a follow-up commit -- so the rule never
points at files that don't exist.

count_v7_endpoints.py's docstring/comments and its "no files found"
error message still described APIMethods*.scala as a fallback
discovery source; its actual discover_version_files() never read them
(Http4s*.scala only), so this is a text-only correction.
…ents

Every APIMethodsNNN.scala left in the tree is now a pure runtime shim
-- a literal alias (val ImplementationsX = Http4sNNN.ImplementationsX)
plus an empty trait, kept only so existing imports still compile. This
redirects every remaining production and test reference to the real
Http4sNNN object directly, clearing the way to delete the 12 shim
files entirely in a follow-up commit.

Production code:
- ResourceDocsAPIMethods.scala: dropped the 6 empty-trait mixins
  (APIMethods220/210/200/140/130/121, confirmed empty by direct read)
  and its 9 APIMethods400.Implementations4_0_0.X call sites, now
  Http4s400.Implementations4_0_0.X.
- APIUtil.scala: two nameOf(...) fully-qualified references
  (APIMethods510/500 -> Http4s510/500).
- OBPAPI5_1_0.scala / OBPAPI6_0_0.scala / OBPAPI5_0_0.scala: dropped
  the APIMethods310/400/500/510 imports and mixins (all confirmed
  empty), consolidated the now-orphaned "re-export so this compiles
  after APIMethods* was replaced with a stub" comments into one
  accurate note per file (the stub isn't just replaced now, it's gone).

~41 test files: mechanical import + reference swap
(code.api.vX.APIMethodsNNN -> code.api.vX.Http4sNNN;
APIMethodsNNN.ImplementationsX -> Http4sNNN.ImplementationsX) across
v3_1_0/v4_0_0/v5_0_0/v5_1_0/v6_0_0 test suites. These are literal
aliases to the same object, so this is a pure text substitution with
no behavior change -- verified by a full test-compile afterward.

Cleaned up stale comments/docs that would otherwise reference deleted
files after the follow-up deletion commit: Http4s600.scala,
Http4s210.scala, Glossary.scala (incl. an ASCII diagram), RateLimitingUtil.scala,
ChatEventPublisher.scala, FAQ.md, and introductory_system_documentation.md
(including removing a logback logger entry targeting a class that
would no longer exist). Left the "Intentional drift from Lift's
APIMethodsNNN.scala source-of-truth" comments elsewhere untouched --
those are historical citations of where a documented behavioral
decision came from, not claims that the file currently exists, so
they stay accurate after the deletion.
Every one of these files had shrunk to a thin runtime shim (object
APIMethodsNNN { val ImplementationsX = Http4sNNN.ImplementationsX })
plus an empty trait, with everything else -- the original Lift
ResourceDoc registrations -- commented out. All production and test
code that imported them was redirected to the real HttpsNNN objects
directly in the previous commit; the parity audit that used to read
their commented-out text now reads scripts/resource_doc_baseline/'s
JSON export instead, verified byte-for-byte lossless against this
exact commit's source before it was allowed to proceed.

APIMethods121.scala, APIMethods130.scala, APIMethods140.scala,
APIMethods200.scala, APIMethods210.scala, APIMethods220.scala,
APIMethods300.scala, APIMethods310.scala, APIMethods400.scala,
APIMethods500.scala, APIMethods510.scala, APIMethods600.scala --
60,634 lines, all net removal, no archive copy kept in the tree
(git history is the archive).

check_lift_http4s_resource_doc_parity.py and
export_and_verify.py --check-only both still pass with these files
gone, confirming the JSON baseline and its digest manifest don't
depend on them being present.
…oints.py

parse_file() hardcoded ResourceDoc constructor argument positions
assuming the pre-Lift-teardown signature (a leading partialFunction
parameter that no longer exists in any current file): name at args[2],
verb at args[3], url at args[4]. Every current Http4sXYZ.scala uses
the post-teardown signature (no leading partialFunction), where those
same fields sit one position earlier. This meant args[3] -- read as
the verb -- was actually the URL string, which never matched
HTTP_VERBS, so every single ResourceDoc registration in every version
file was silently discarded with a WARN and the script always reported
0 total endpoints.

Fixed by detecting which signature a given call uses (checking whether
args[2] looks like an HTTP verb literal) and computing the field
positions from that, the same way check_lift_http4s_resource_doc_parity.py
already does with its POSITIONAL_FIELDS / CURRENT_POSITIONAL_FIELDS
split -- instead of a second hardcoded guess that had drifted out of
sync with it.

Confirmed via direct testing: parse_file on v1.2.1 alone went from
0 docs / 0 stderr warnings suppressed as "unexpected verb" (all 70
silently dropped) to 70 docs matched correctly. Full run now reports
852 endpoints reachable via /obp/v7.0.0/ with zero stderr warnings,
in the same ballpark as V7ResourceDocsAggregationTest's independently
measured 858 (the two won't match exactly -- this script's dedup/
exclude logic is a separate, simpler reimplementation of the runtime
aggregation, not the same code path).
getAllJsonSchemaValidationsPublic and getAllAuthenticationTypeValidationsPublic
are new v4.0.0 endpoints, so FrozenClassUtil's persisted snapshot needs
regenerating to reflect the expected count increase.
Adds the two new v4.0.0 public endpoints to the text sibling. Also
picks up APIUtil.JArrayBody dropping out of the reachable type set -
that type stopped being reachable from any STABLE endpoint body before
this branch started (confirmed against origin/develop), so this is
stale-fixture drift the regeneration corrects, not a change introduced
by this branch.
--allowlist was read without checking where it pointed, and the version
positional was interpolated straight into a baseline filename. Constrain
the former to the repo root and require the latter to match the same
vN_N_N pattern the auto-discovery path already enforces.
The aggregation reached back into OBPAPI4_0_0/5_1_0/6_0_0 for these three
lists, which is the last thing tying it to the aggregator objects. nameOf
is a compile-time macro over the member name, so sourcing it from
Http4sNNN.ImplementationsX yields the identical strings.
Http4s500/Http4s510 already declare their own versionStatus, so the root
endpoints can read version and status locally instead of borrowing them
from the aggregator. ResourceDocsAPIMethods' twelve OBPAPI imports and
ObpGrpcServer's were unused, and APIUtil only wanted Implementations2_2_0,
which Http4s220 exposes directly.
The aggregators only re-exported other objects' members, so each reference
has an exact equivalent. Note the mapping keys off the Implementations
number rather than the OBPAPI one: OBPAPI3_0_0.Implementations2_2_0 is
Http4s220.Implementations2_2_0. allResourceDocs becomes the corresponding
Http4sResourceDocAggregation catalog.
FrozenClassUtil recovered the version list by scanning for VersionedOBPApis
implementors, which in practice meant the OBPAPIx_x_x objects. Http4sResourceDocAggregation
already had to name all twelve versions, so it now also exposes their status
and cumulative catalogs and the scan becomes a plain list.

versionStatus is still read from each Http4sNxx rather than restated, so there
remains one declaration per version. The frozen fixtures were produced by the
old scan and still match byte for byte, which is what makes the two paths
provably equivalent.
Nothing references them any more: the resource-doc aggregation, the
excludeEndpoints lists, the version/status pairs and every test reference
now come from Http4sResourceDocAggregation or the Http4sNxx objects
directly. Removes the last Lift OBPRestHelper subclasses in the versioned
API packages.
Its only consumer was FrozenClassUtil's classpath scan, and its only
remaining implementors were the two dynamic aggregators, whose members are
read directly rather than through the trait. Also refreshes the comments
and frozen-test scenario names that still described the deleted objects.
The lists moved into Http4sResourceDocAggregation as excludeEndpointsV{nnn},
so the per-version lookup found nothing and the script stopped filtering:
it reported 871 reachable endpoints instead of 852. Match the suffixed names
and the count is right again (6/8/14 excludes for v4.0.0/v5.1.0/v6.0.0).
v121 was the one catalog that did not force its own Implementations object,
on the grounds that Http4sApp startup always did it. The deleted OBPAPI
objects were quietly doing it too, from their static initializers, so a
caller that reads a catalog without booting a server no longer has that
cover. Every later catalog snapshots v121 into a new buffer, so an
unpopulated one would drop v1.2.1 from the whole chain for the life of
the JVM.
Both scripts picked the constructor layout by testing whether positional 2
held a verb literal, and fell back to the pre-teardown layout otherwise.
Anything they could not classify was therefore patched at offsets shifted by
one, writing each field's text into its neighbour's slot -- in a file they
rewrite in place.

Require a verb literal at exactly one of positional 2 and 3, and on anything
else warn with the file and line, skip the registration and exit non-zero
rather than guess.
The step ran after all four shards but allocated its ports with
`alloc_free_port || exit 1`, so a transient allocation failure exited before
the summary, the per-shard diagnostics and the Surefire audit -- discarding
results that were already computed. Record a failing RC and carry on instead.
@sonarqubecloud

sonarqubecloud Bot commented Sep 1, 2026

Copy link
Copy Markdown

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