Skip to content

test(phase8 #44 H3): provider-aware Hurl sync to /api/v2 + v1 ghost guard#1675

Merged
earayu merged 1 commit into
mainfrom
bryce/phase8-task44-h3-provider-hurl-sync
Apr 25, 2026
Merged

test(phase8 #44 H3): provider-aware Hurl sync to /api/v2 + v1 ghost guard#1675
earayu merged 1 commit into
mainfrom
bryce/phase8-task44-h3-provider-hurl-sync

Conversation

@earayu
Copy link
Copy Markdown
Collaborator

@earayu earayu commented Apr 25, 2026

Summary

Phase 8 第二批 task #44 (H3 — provider-aware Hurl sync after /api/v1 ghost hard-cut). Sibling to #43 (H1 ruff format sweep, weihong) and #46 (H4 graceful chat collection, chenyexuan).

Per architect canonical D7-1 (msg=8b6b4bc3) /api/v1/embeddings and /api/v1/rerank are pinned as permanent OpenAI-compat mounts. The other v1 LLM provider routes (/api/v1/llm_configuration, /api/v1/llm_providers/*, /api/v1/available_models, /api/v1/default_models) were already removed from main when providers_v2_routes.py shipped, so the provider-aware Hurl test was hitting 404s and bringing e2e-http-smoke red on every Phase 8 first-batch PR (root cause flagged in #41 H3 evidence by weihong).

Changes

  • tests/e2e_http/hurl/full/10_provider_llm.hurl — rewrite all internal provider/model/default CRUD calls to /api/v2/providers/* and /api/v2/default-models. Keep /api/v1/embeddings and /api/v1/rerank calls unchanged (allowlist). Adjust the create-model body to drop provider_name (now path param in v2) and the delete-model assertion to expect 204 (v2 pure-command contract).
  • tests/unit_test/test_provider_v2_openapi_contract.py — empty out PROVIDER_V1_GHOST_PATHS baseline; the v1 LLM provider routes are no longer mounted, so the inventory baseline shrinks to zero and the existing stability test now strictly forbids regrowth.
  • tests/unit_test/test_v1_ghost_guard.py — new negative-allowlist guard that scans tests/e2e_http/hurl/** and asserts every /api/v1/... literal matches either the OpenAI-compat permanent allowlist (/api/v1/embeddings, /api/v1/rerank) or the transitional pre-migration set (apikeys, audit, marketplace, prompts, settings, export, collections, chats, quotas, system, bots, test). Each follow-up G* PR shrinks TRANSITIONAL_V1_PREFIXES as it migrates the corresponding domain to /api/v2.

Net: +136 / -29 LOC (1 new test file 115 LOC, 2 edits).

Scope discipline

This PR strictly does not include:

  • G5 dead-route caller cleanup outside provider lane (FE quotas/admin/document/marketplace/bot, pytest fixtures) — covered by future G* tasks
  • Any backend route changes — backend already removed these routes in earlier work
  • Format sweep on other files (handled by [BUG] get_collections_cron_job failed  #43 H1 — weihong)

Test plan

  • uv run python -m pytest tests/unit_test/test_v1_ghost_guard.py tests/unit_test/test_provider_v2_openapi_contract.py tests/unit_test/test_modularization_boundaries.py -x -q28 passed
  • uv run python -m pytest tests/unit_test -q --deselect 'tests/unit_test/test_web_typed_api_contract.py::test_phase1_fe_complete_identity_auth_admin_audit_adapter_boundary'688 passed / 28 skipped / 1 deselected / 0 failed
  • uv run ruff check aperag/ tests/ config/ → clean
  • uv run ruff format --check tests/unit_test/test_v1_ghost_guard.py → clean (other tests/ format drift is mainline existing, scoped to [BUG] get_collections_cron_job failed  #43 H1)
  • e2e-http-smoke full/10_provider_llm.hurl — runs in CI; expected to no longer 404 on /api/v1/llm_configuration etc.

CR ask

@weston blocker-level minimal CR — write-set is provider-aware Hurl + 2 unit tests; no backend touched.
@符炫炜 canonical drift quick check — preserve allowlist (embeddings/rerank), no scope creep into G5.

🤖 Generated with Claude Code

…uard

Per architect canonical D7-1 (msg=8b6b4bc3) the OpenAI-compatible
``/api/v1/embeddings`` and ``/api/v1/rerank`` endpoints are pinned as
permanent ``/api/v1`` mounts. The other v1 LLM provider routes
(``/api/v1/llm_configuration``, ``/api/v1/llm_providers/*``,
``/api/v1/available_models``, ``/api/v1/default_models``) were already
removed from main when ``providers_v2_routes.py`` shipped, so the
provider-aware Hurl test was hitting 404s and bringing
``e2e-http-smoke`` red on every PR.

Changes:
- ``tests/e2e_http/hurl/full/10_provider_llm.hurl`` — rewrite all
  internal provider/model/default CRUD calls to ``/api/v2/providers/*``
  and ``/api/v2/default-models``. Keep ``/api/v1/embeddings`` and
  ``/api/v1/rerank`` calls unchanged (OpenAI-compat allowlist). Adjust
  the create-model body to drop ``provider_name`` (now a path param in
  v2) and the delete-model assertion to expect 204 (v2 pure-command
  contract).
- ``tests/unit_test/test_provider_v2_openapi_contract.py`` — empty out
  ``PROVIDER_V1_GHOST_PATHS`` baseline; the v1 LLM provider routes are
  no longer mounted, so the inventory baseline shrinks to zero and the
  existing stability test now strictly forbids regrowth.
- ``tests/unit_test/test_v1_ghost_guard.py`` — new negative-allowlist
  guard that scans ``tests/e2e_http/hurl/**`` and asserts every
  ``/api/v1/...`` literal matches either the OpenAI-compat permanent
  allowlist or the transitional pre-migration set (apikeys, audit,
  marketplace, prompts, settings, export, collections, chats, quotas,
  system, bots, test). Each follow-up G* PR shrinks
  ``TRANSITIONAL_V1_PREFIXES`` as it migrates the corresponding domain
  to ``/api/v2``.
@earayu earayu merged commit 12e5671 into main Apr 25, 2026
0 of 2 checks passed
@earayu earayu deleted the bryce/phase8-task44-h3-provider-hurl-sync branch April 25, 2026 08:59
earayu added a commit that referenced this pull request Apr 25, 2026
…s hard-cut

Phase 8 second batch G4a — per architect canonical D7-2 (msg=94f663f2 §3.2.2)
+ Option A locked (msg=25a30445), the legacy combined ``governance_router``
(which mounted both API keys and audit logs at ``/api/v1``) is split into two
single-purpose routers so #50 G4a (audit-logs) and #51 G4b (apikeys) can
migrate to ``/api/v2`` independently.

This PR lands the audit-logs side: ``/api/v1/audit-logs*`` is hard-cut to
``/api/v2/audit-logs*`` (no v1 alias). The ``aperag/openapi_spec.py:23``
hidden filter is preserved so audit-logs stay outside the public OpenAPI
spec. The apikeys router stays at ``/api/v1/apikeys*`` for now — #51 will
flip its mount to ``/api/v2`` in a 1-line follow-up.

File structure follows architect-recommended (β) pattern: per-router file,
matching the convention of #36 / G1 / G2 / G3 / G4d carved routers.

Changes:

* Rename ``aperag/domains/governance/api/routes.py`` →
  ``aperag/domains/governance/api/audit_routes.py``; trim it to only audit
  routes + needed imports.
* New ``aperag/domains/governance/api/apikeys_routes.py`` — apikey routes +
  needed imports; identical handler signatures (no behavior change).
* ``aperag/app.py`` — replace single ``governance_router`` import + mount
  with two imports and split mounts:
  ``audit_router → /api/v2`` (this PR's hard-cut),
  ``apikeys_router → /api/v1`` (preserved; #51 will flip).
* New boundary test
  ``test_no_module_imports_legacy_governance_routes`` — analogous to
  ``test_no_module_imports_legacy_views_settings`` from #48, forbids re-import
  of the deleted combined ``aperag.domains.governance.api.routes`` module.
  Total boundary tests now 23.
* ``tests/unit_test/test_v1_ghost_guard.py`` — TRANSITIONAL_V1_PREFIXES
  shrinks ``/api/v1/audit-logs`` (G4a removed). 11 → 10 prefixes remaining,
  matching the "clean as you go" pattern established in #1675 H3.

FE follow-up: ``web/src/features/audit/{client,server}-api.ts`` v1→v2
caller sync will be a sibling PR by @dongdong (per architect spec) once the
backend OpenAPI diff is available.

Gates: 25/25 boundary + ghost guard, 698 pass / 29 skip / 1 deselect / 0
fail unit suite, ruff check + format clean.
earayu added a commit that referenced this pull request Apr 25, 2026
…s hard-cut (#1684)

* refactor(phase8 #50 G4a): split governance routes + /api/v2/audit-logs hard-cut

Phase 8 second batch G4a — per architect canonical D7-2 (msg=94f663f2 §3.2.2)
+ Option A locked (msg=25a30445), the legacy combined ``governance_router``
(which mounted both API keys and audit logs at ``/api/v1``) is split into two
single-purpose routers so #50 G4a (audit-logs) and #51 G4b (apikeys) can
migrate to ``/api/v2`` independently.

This PR lands the audit-logs side: ``/api/v1/audit-logs*`` is hard-cut to
``/api/v2/audit-logs*`` (no v1 alias). The ``aperag/openapi_spec.py:23``
hidden filter is preserved so audit-logs stay outside the public OpenAPI
spec. The apikeys router stays at ``/api/v1/apikeys*`` for now — #51 will
flip its mount to ``/api/v2`` in a 1-line follow-up.

File structure follows architect-recommended (β) pattern: per-router file,
matching the convention of #36 / G1 / G2 / G3 / G4d carved routers.

Changes:

* Rename ``aperag/domains/governance/api/routes.py`` →
  ``aperag/domains/governance/api/audit_routes.py``; trim it to only audit
  routes + needed imports.
* New ``aperag/domains/governance/api/apikeys_routes.py`` — apikey routes +
  needed imports; identical handler signatures (no behavior change).
* ``aperag/app.py`` — replace single ``governance_router`` import + mount
  with two imports and split mounts:
  ``audit_router → /api/v2`` (this PR's hard-cut),
  ``apikeys_router → /api/v1`` (preserved; #51 will flip).
* New boundary test
  ``test_no_module_imports_legacy_governance_routes`` — analogous to
  ``test_no_module_imports_legacy_views_settings`` from #48, forbids re-import
  of the deleted combined ``aperag.domains.governance.api.routes`` module.
  Total boundary tests now 23.
* ``tests/unit_test/test_v1_ghost_guard.py`` — TRANSITIONAL_V1_PREFIXES
  shrinks ``/api/v1/audit-logs`` (G4a removed). 11 → 10 prefixes remaining,
  matching the "clean as you go" pattern established in #1675 H3.

FE follow-up: ``web/src/features/audit/{client,server}-api.ts`` v1→v2
caller sync will be a sibling PR by @dongdong (per architect spec) once the
backend OpenAPI diff is available.

Gates: 25/25 boundary + ghost guard, 698 pass / 29 skip / 1 deselect / 0
fail unit suite, ruff check + format clean.

* fix(phase8 #50 G4a): sync HIDDEN_FROM_PUBLIC_PATH_PREFIXES audit-logs to /api/v2 + add regression guard

Per @chenyexuan replacement CR (msg=1b0fe11c) — the original G4a backend
correctly mounted the audit router at ``/api/v2`` but missed updating the
``HIDDEN_FROM_PUBLIC_PATH_PREFIXES`` filter in ``aperag/openapi_spec.py``,
which was still keyed on ``/api/v1/audit-logs``. After the mount switch
the filter no longer matched any path, leaking ``/api/v2/audit-logs*``
into the public OpenAPI spec — a violation of D7-2 ``hidden 保持`` and
architect canonical msg=25a30445.

Fix:

- ``aperag/openapi_spec.py:23`` — flip prefix from
  ``/api/v1/audit-logs`` → ``/api/v2/audit-logs``. One-line.
- ``tests/unit_test/test_openapi_spec.py``:
  - Update the existing synthetic-spec filter test to assert v2 paths
    (was v1; the assertion would otherwise pass vacuously after the
    real prefix changed).
  - Add new ``test_audit_logs_hidden_from_public_openapi_for_live_app``
    — runs the real ``aperag.app`` through ``build_full_openapi_spec``
    + ``filter_public_openapi`` and asserts no audit-logs path leaks
    into the public spec. This is the regression guard the architect
    + reviewer recommended so a future refactor cannot silently re-leak.

No other write set in scope. Pure 1-line canonical fix + 1 new test +
1 small test rewrite. The Option A router split, mount changes,
boundary gate, ghost guard shrink, and #51 hand-off shape from the
original PR head are unchanged.
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