Auditable one-to-one map of every PHP OAuth functional/security test method to its named Go test/subtest evidence, mechanically verified by fonoteka.go/parity/oauth_audit_test.go's TestPHPTestMap.
22 KiB
Phase 08 PHP OAuth Test Map
D-18: every PHP OAuth functional/security test method maps to a named passing Go test/subtest.
Distribution (exactly 103 unique PHP method rows): authorize 11, client-command 8, metadata 2, migration 7, register 10, token 10, consent/scope-ceiling 7, refresh-rotation 10, revocation 8, surface-isolation 30.
parity/oauth_audit_test.go's TestPHPTestMap parses this table mechanically and
fails if any row is missing, duplicated, or points at a Go test/subtest that does
not exist in the stated package. Column Repo is summercms.go or fonoteka.go
(sibling directories in the meta repo). Column Go Package is a Go import-style
relative path from that repo's root. Subtest is empty for a bare top-level
func TestX(t *testing.T).
Deferred-scope notice
Several security/TokenSurfaceIsolationTest.php rows (and one
security/OAuthRevocationTest.php row) exercise route families Phase 8 does not
port (albums, discogs, csv import, wishlist, collection share/switch,
oauth-identities, public share) per 08-CONTEXT.md's Phase Boundary and
PROJECT.md's still-Active "All 154 Płytarium API routes ported" requirement.
Those rows are marked deferred-scope in Notes: the named Go subtest asserts the
honest current state (the route family does not exist in the assembled table
yet), not the full PHP behavior, which cannot exist until a later phase ports
the feature. OAuthMigrationTest's four v119 rows are marked
architecture-difference: 08-02-PLAN.md folded scope_ceiling directly into
the initial CREATE TABLE instead of a second incremental migration, so there
is no separate Go migration step to test add/idempotent/down/missing-table-noop
against in isolation; the named subtests assert the real equivalent fact this
architecture produces.
authorize (functional/OAuthAuthorizeTest.php, 11)
| PHP Method | Repo | Go Package | Go Test | Subtest | Notes |
|---|---|---|---|---|---|
| test_unknown_client_returns_400_with_no_location | summercms.go | wristband | TestAuthorizeUnknownClientReturnsLocal400NoLocation | ||
| test_unregistered_redirect_uri_returns_400_with_no_location | summercms.go | wristband | TestAuthorizeUnregisteredRedirectURIReturnsLocal400NoLocation | ||
| test_trailing_slash_mismatch_is_unregistered | summercms.go | wristband | TestAuthorizeTrailingSlashMismatchIsUnregistered | ||
| test_plain_pkce_redirects_with_invalid_request_and_preserves_state | summercms.go | wristband | TestPKCEChallengeMethodMustBeS256 | ||
| test_valid_request_redirects_to_connect_with_opaque_handle_only | summercms.go | wristband | TestAuthorizeValidRequestRedirectsToConnectWithOpaqueHandleOnly | ||
| test_iss_is_present_on_every_error_redirect | summercms.go | wristband | TestAuthorizeIssIsPresentOnEveryErrorRedirect | ||
| test_null_ceiling_preserves_ai_scope | summercms.go | wristband | TestAuthorizeNullCeilingPreservesAiScope | ||
| test_ceiling_truncates_ai_without_error | summercms.go | wristband | TestAuthorizeCeilingTruncatesAiWithoutError | ||
| test_ceiling_preserves_offline_access_flag | summercms.go | wristband | TestAuthorizeCeilingPreservesOfflineAccessFlag | ||
| test_ceiling_rejects_ai_only_as_invalid_scope_on_trusted_redirect | summercms.go | wristband | TestAuthorizeCeilingRejectsAiOnlyAsInvalidScopeOnTrustedRedirect | ||
| test_ceiling_rejects_ai_plus_offline_access_as_invalid_scope | summercms.go | wristband | TestAuthorizeCeilingRejectsAiPlusOfflineAccessAsInvalidScope |
client-command (functional/OAuthClientCommandTest.php, 8)
| PHP Method | Repo | Go Package | Go Test | Subtest | Notes |
|---|---|---|---|---|---|
| test_list_prints_client_id_and_uris_never_the_secret | fonoteka.go | plugins/golem15/fonoteka/console | TestOAuthClientCommandListPrintsClientIDAndURIsNeverTheSecret | ||
| test_client_id_adds_redirect_uri_without_rotating_secret | fonoteka.go | plugins/golem15/fonoteka/console | TestOAuthClientCommandAddRedirectURIsWithoutRotatingSecret | ||
| test_unknown_client_id_fails | fonoteka.go | plugins/golem15/fonoteka/console | TestOAuthClientCommandUnknownClientIDFails | ||
| test_scope_option_persists_read_write_ceiling | fonoteka.go | plugins/golem15/fonoteka/console | TestOAuthClientCommandScopeCeilingPersistsAndListsNeverTheSecret | one Go test, 3 distinct assertions -> 3 PHP methods (this row + next 2) | |
| test_absent_scope_option_stores_null_ceiling | fonoteka.go | plugins/golem15/fonoteka/console | TestOAuthClientCommandScopeCeilingPersistsAndListsNeverTheSecret | ||
| test_invalid_scope_fails_without_creating_a_client | fonoteka.go | plugins/golem15/fonoteka/console | TestOAuthClientCommandInvalidScopeFailsWithoutCreatingAClient | ||
| test_list_prints_scope_ceiling_never_the_secret | fonoteka.go | plugins/golem15/fonoteka/console | TestOAuthClientCommandScopeCeilingPersistsAndListsNeverTheSecret | ||
| test_client_id_adds_redirect_uri_without_changing_ceiling | fonoteka.go | plugins/golem15/fonoteka/console | TestOAuthClientCommandAddRedirectURIWithoutChangingCeiling | new (08-10 Task 1) |
metadata (functional/OAuthMetadataTest.php, 2)
| PHP Method | Repo | Go Package | Go Test | Subtest | Notes |
|---|---|---|---|---|---|
| test_authorization_server_metadata_is_unwrapped_rfc8414_document | fonoteka.go | plugins/golem15/fonoteka | TestOAuthMetadataAssembled | ||
| test_authorize_without_client_is_local_error_and_register_exists | fonoteka.go | plugins/golem15/fonoteka | TestOAuthMetadataAuthorizeWithoutClientIsLocalErrorAndRegisterExists | new (08-10 Task 1) |
migration (functional/OAuthMigrationTest.php, 7)
| PHP Method | Repo | Go Package | Go Test | Subtest | Notes |
|---|---|---|---|---|---|
| test_v117_creates_three_oauth_tables_and_named_unique_indexes | fonoteka.go | plugins/golem15/fonoteka/updates | TestOAuthMigrationV117CreatesThreeOAuthTablesAndNamedUniqueIndexes | new (08-10 Task 1) | |
| test_v117_second_up_is_idempotent | fonoteka.go | plugins/golem15/fonoteka/updates | TestOAuthMigrationV117SecondUpIsIdempotent | new; proven at the gormigrate re-Migrate() boundary, not a raw double-func-call | |
| test_v117_down_drops_the_three_oauth_tables | fonoteka.go | plugins/golem15/fonoteka/updates | TestOAuthMigrationV117DownDropsTheThreeOAuthTables | new | |
| test_v119_adds_nullable_scope_ceiling | fonoteka.go | plugins/golem15/fonoteka/updates | TestOAuthMigrationV119ScopeCeilingBakedIntoInitialSchema | test_v119_adds_nullable_scope_ceiling | architecture-difference: see notice above |
| test_v119_second_up_is_idempotent | fonoteka.go | plugins/golem15/fonoteka/updates | TestOAuthMigrationV119ScopeCeilingBakedIntoInitialSchema | test_v119_second_up_is_idempotent | architecture-difference |
| test_v119_down_drops_scope_ceiling | fonoteka.go | plugins/golem15/fonoteka/updates | TestOAuthMigrationV119ScopeCeilingBakedIntoInitialSchema | test_v119_down_drops_scope_ceiling | architecture-difference |
| test_v119_up_on_missing_table_is_noop | fonoteka.go | plugins/golem15/fonoteka/updates | TestOAuthMigrationV119ScopeCeilingBakedIntoInitialSchema | test_v119_up_on_missing_table_is_noop | architecture-difference |
register (functional/OAuthRegisterTest.php, 10)
| PHP Method | Repo | Go Package | Go Test | Subtest | Notes |
|---|---|---|---|---|---|
| test_public_client_is_issued_without_a_secret | summercms.go | wristband | TestRegisterPublicClientResponse | ||
| test_omitted_auth_method_defaults_to_public | summercms.go | wristband | TestRegisterPublicClientResponse | same test, 2nd distinct assertion (token_endpoint_auth_method="none") | |
| test_confidential_client_returns_secret_once | summercms.go | wristband | TestRegisterConfidentialClientReturnsSecretOnce | ||
| test_http_non_loopback_and_javascript_uris_are_rejected | summercms.go | wristband | TestRegisterJavascriptURIIsRejected | new (08-10 Task 1); http-non-loopback half already in TestRegisterRedirectURIBounds/http-non-loopback | |
| test_loopback_http_is_accepted | summercms.go | wristband | TestRegisterLoopbackHTTPIsAccepted | new | |
| test_missing_redirect_uris_is_invalid | summercms.go | wristband | TestRegisterRedirectURIBounds | missing | |
| test_form_urlencoded_is_rejected | summercms.go | wristband | TestRegisterWrongContentType | ||
| test_orphan_sweep_deletes_stale_dcr_rows_not_artisan_clients | summercms.go | wristband | TestRegisterSweepsStaleUnconsentedButKeepsArtisanClients | ||
| test_registered_public_client_can_authorize_and_exchange_without_secret | fonoteka.go | parity | TestOAuthFlows | full recorded 17-step lifecycle includes a public-client authorize+exchange leg | |
| test_error_body_has_no_secret_or_stack | summercms.go | wristband | TestRegisterErrorBodyHasNoSecretOrStackTrace | new |
token (functional/OAuthTokenTest.php, 10)
| PHP Method | Repo | Go Package | Go Test | Subtest | Notes |
|---|---|---|---|---|---|
| test_valid_code_returns_bearer_inv_token | fonoteka.go | plugins/golem15/fonoteka/classes/auth | TestOAuthCodeExchangeMintsInvAccessAndRefreshTokens | ||
| test_access_token_authenticates_me_with_granted_scopes_and_collections | fonoteka.go | parity | TestOAuthFlows | "me" step replays the real /api/v1/fonoteka/me response against an OAuth-exchanged token | |
| test_replaying_the_code_returns_invalid_grant | summercms.go | wristband | TestTokenCodeSequentialReplayIsInvalidGrantSecondTime | ||
| test_wrong_verifier_returns_invalid_grant | summercms.go | wristband | TestTokenWrongVerifierIsInvalidGrant | ||
| test_wrong_client_secret_returns_invalid_client | summercms.go | wristband | TestTokenConfidentialClientWrongSecretIsInvalidClient | ||
| test_json_body_does_not_five_hundred | summercms.go | wristband | TestTokenRejectsJSONBodyEvenWithValidQueryParams | ||
| test_offline_access_is_echoed_but_not_persisted_on_api_token | fonoteka.go | plugins/golem15/fonoteka/classes/auth | TestOAuthOfflineAccessEchoedButNotPersistedOnAPIToken | new (08-10 Task 1) | |
| test_scope_omits_offline_access_when_not_requested | fonoteka.go | plugins/golem15/fonoteka/classes/auth | TestOAuthScopeOmitsOfflineAccessWhenNotRequested | new | |
| test_public_client_exchanges_code_without_secret | summercms.go | wristband | TestTokenPublicClientIgnoresSuppliedSecret | ||
| test_confidential_client_without_secret_is_invalid_client | summercms.go | wristband | TestTokenConfidentialClientMissingSecretIsInvalidClient |
consent/scope-ceiling (security/OAuthConsentScopeCeilingTest.php, 7)
| PHP Method | Repo | Go Package | Go Test | Subtest | Notes |
|---|---|---|---|---|---|
| test_consent_requesting_ai_when_client_asked_read_grants_read_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthConsentIntersectionGrantsOnlyOriginallyRequestedScopes | new (08-10 Task 1) | |
| test_consent_submitting_a_scope_outside_mintable_is_422 | fonoteka.go | plugins/golem15/fonoteka | TestOAuthConsentEmptySubmittedScopeIntersectionIs422 | ||
| test_submitted_inaccessible_collection_id_never_enters_the_grant | fonoteka.go | plugins/golem15/fonoteka | TestOAuthConsentCollectionIDsAlwaysServerResolvedActivePin | new; collection_ids is never read from the request body at all (architecturally stronger than PHP's runtime filter) | |
| test_issued_collection_ids_equal_the_active_pin | fonoteka.go | plugins/golem15/fonoteka | TestOAuthConsentCollectionIDsAlwaysServerResolvedActivePin | same test, 2nd distinct assertion | |
| test_second_consent_on_the_same_request_id_fails | fonoteka.go | plugins/golem15/fonoteka | TestOAuthConsentSecondConsentOnSameRequestIDFails | new | |
| test_show_returns_host_and_pinned_name_without_collection_id | fonoteka.go | plugins/golem15/fonoteka | TestOAuthConsentShowExactKeySet | new | |
| test_authorize_route_ceiling_drops_ai_from_scopes_requested | fonoteka.go | plugins/golem15/fonoteka | TestOAuthConsentScopeCeilingViaShow |
refresh-rotation (security/OAuthRefreshRotationTest.php, 10)
| PHP Method | Repo | Go Package | Go Test | Subtest | Notes |
|---|---|---|---|---|---|
| test_s256_verification_accepts_matching_verifier | fonoteka.go | plugins/golem15/fonoteka/classes/auth | TestOAuthCodeExchangeMintsInvAccessAndRefreshTokens | real-Postgres positive S256 match | |
| test_s256_verification_rejects_wrong_verifier | fonoteka.go | plugins/golem15/fonoteka/classes/auth | TestOAuthCodeExchangeWrongVerifierIsInvalidGrantAndMintsNothing | ||
| test_plain_pkce_is_rejected_even_when_verifier_equals_challenge | summercms.go | wristband | TestTokenPlainPKCEIsRejectedEvenWhenVerifierEqualsChallenge | new (08-10 Task 1) | |
| test_code_cannot_be_exchanged_twice | summercms.go | wristband | TestTokenCodeSequentialReplayIsInvalidGrantSecondTime | ||
| test_expired_code_is_rejected | summercms.go | wristband | TestTokenExpiredCodeIsInvalidGrant | ||
| test_code_with_different_redirect_uri_is_rejected | summercms.go | wristband | TestTokenRedirectURIMismatchIsInvalidGrant | ||
| test_code_presented_by_a_different_client_is_rejected | summercms.go | wristband | TestTokenClientMismatchIsInvalidGrant | ||
| test_rotation_issues_a_new_refresh_and_marks_the_old_one_rotated | summercms.go | wristband | TestRefreshRotationIssuesNewPairAndKeepsPredecessorAsEvidence | ||
| test_replaying_rotated_refresh_revokes_the_entire_chain | fonoteka.go | plugins/golem15/fonoteka/classes/auth | TestOAuthRefreshReplayRevokesLineageAndBothAccessTokens | ||
| test_revoke_chain_leaves_no_usable_api_token | fonoteka.go | plugins/golem15/fonoteka/classes/auth | TestOAuthConnectedAppRevokeStoreKillsAccessAndLineage |
revocation (security/OAuthRevocationTest.php, 8)
| PHP Method | Repo | Go Package | Go Test | Subtest | Notes |
|---|---|---|---|---|---|
| test_connected_app_revoke_kills_access_and_refresh | fonoteka.go | plugins/golem15/fonoteka | TestConnectedAppsRevokeKillsAccessAndRefreshThenDisappearsFromList | ||
| test_rotated_predecessor_is_dead_after_connected_app_revoke | fonoteka.go | plugins/golem15/fonoteka | TestOAuthRevocationRotatedPredecessorIsDeadAfterConnectedAppRevoke | new (08-10 Task 1) | |
| test_manual_token_route_on_oauth_token_kills_refresh_chain | fonoteka.go | plugins/golem15/fonoteka | TestOAuthRevocationManualTokenRouteKillsRefreshChain | new; GREEN companion of this plan's Rule-1 fix to controllers/api/token_api_controller.go Destroy | |
| test_foreign_or_missing_connected_app_id_returns_404_never_403 | fonoteka.go | plugins/golem15/fonoteka | TestConnectedAppsRevokeForeignAndMissingAndManualShareExact404 | ||
| test_second_consent_survives_revoking_the_first | fonoteka.go | plugins/golem15/fonoteka | TestOAuthRevocationSecondGrantSurvivesRevokingFirst | new | |
| test_oauth_token_reading_album_outside_allow_list_is_404_never_403 | fonoteka.go | plugins/golem15/fonoteka | TestOAuthRevocationReadingOutsideAllowListRouteNotYetPorted | new; deferred-scope (albums unported, see notice above) | |
| test_revoked_and_rotated_oauth_tokens_leave_the_connected_apps_list | fonoteka.go | plugins/golem15/fonoteka | TestOAuthRevocationRotatedTokenLeavesExactlyOneConnectedApp | new; revoke-then-empty half covered by TestOAuthRevocationListsSignalEachOtherExcludingOAuthFromManual | |
| test_lists_signal_each_other_and_oauth_tokens_are_absent_from_manual_list | fonoteka.go | plugins/golem15/fonoteka | TestOAuthRevocationListsSignalEachOtherExcludingOAuthFromManual | new |
surface-isolation (security/TokenSurfaceIsolationTest.php, 30)
| PHP Method | Repo | Go Package | Go Test | Subtest | Notes |
|---|---|---|---|---|---|
| test_final_surfaces_have_flat_albums_and_no_legacy_hierarchy_routes | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_final_surfaces_have_flat_albums_and_no_legacy_hierarchy_routes | deferred-scope: albums unported |
| test_token_surface_excludes_collection_create_membership_and_token_management | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_token_surface_excludes_collection_create_membership_and_token_management | real: token surface has exactly genres+me today |
| test_fixed_album_routes_precede_numeric_album_route | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_fixed_album_routes_precede_numeric_album_route | deferred-scope |
| test_jwt_group_carries_no_token_scope_middleware | fonoteka.go | plugins/golem15/fonoteka | TestFullRouteTableAuthGroupMutualExclusivity | existing Phase 6 test (T-06-02/T-06-10), walks the real assembled table | |
| test_read_only_token_is_forbidden_on_write_and_ai_routes | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_read_only_token_is_forbidden_on_write_and_ai_routes | deferred-scope: no write/ai-scoped route exists yet |
| test_discogs_import_route_exists_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_discogs_import_route_exists_on_jwt_surface_only | deferred-scope: discogs unported |
| test_csv_import_routes_exist_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_csv_import_routes_exist_on_jwt_surface_only | deferred-scope: csv import unported |
| test_discogs_credential_routes_exist_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_discogs_credential_routes_exist_on_jwt_surface_only | deferred-scope |
| test_oauth_identity_routes_exist_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_oauth_identity_routes_exist_on_jwt_surface_only | deferred-scope: social login explicitly out of scope (08-CONTEXT.md) |
| test_album_stats_route_exists_on_jwt_and_token_surfaces | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_album_stats_route_exists_on_jwt_and_token_surfaces | deferred-scope |
| test_album_sync_route_exists_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_album_sync_route_exists_on_jwt_surface_only | deferred-scope |
| test_album_missing_route_exists_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_album_missing_route_exists_on_jwt_surface_only | deferred-scope |
| test_album_match_and_apply_routes_exist_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_album_match_and_apply_routes_exist_on_jwt_surface_only | deferred-scope |
| test_wishlist_match_and_apply_routes_exist_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_wishlist_match_and_apply_routes_exist_on_jwt_surface_only | deferred-scope: wishlist unported |
| test_token_surface_wishlist_album_routes_are_index_store_update_destroy_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_token_surface_wishlist_album_routes_are_index_store_update_destroy_only | deferred-scope |
| test_collection_share_routes_exist_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_collection_share_routes_exist_on_jwt_surface_only | deferred-scope |
| test_wishlist_share_routes_exist_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_wishlist_share_routes_exist_on_jwt_surface_only | deferred-scope |
| test_me_locale_routes_exist_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_me_locale_routes_exist_on_jwt_surface_only | real: /_fonoteka/api/v1/me/locale exists on jwt surface only |
| test_collection_switch_route_exists_on_jwt_surface_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_collection_switch_route_exists_on_jwt_surface_only | deferred-scope |
| test_public_share_routes_are_get_only_and_absent_from_token_surface | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_public_share_routes_are_get_only_and_absent_from_token_surface | deferred-scope: public_share group registers zero routes today |
| test_public_wishlist_share_routes_are_get_only_and_absent_from_token_surface | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_public_wishlist_share_routes_are_get_only_and_absent_from_token_surface | deferred-scope |
| test_public_group_carries_no_jwt_or_scope_middleware | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_public_group_carries_no_jwt_or_scope_middleware | deferred-scope: no route registered in this group yet |
| test_missing_token_returns_401_and_write_token_reaches_collection_update | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_missing_token_returns_401_and_write_token_reaches_collection_update | deferred-scope: no collection-update route yet |
| test_oauth_mcp_routes_carry_neither_jwt_scope_nor_web_middleware | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_oauth_mcp_routes_carry_neither_jwt_scope_nor_web_middleware | real |
| test_oauth_mcp_routes_resolve_to_fonoteka_not_social_auth | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_oauth_mcp_routes_resolve_to_fonoteka_not_social_auth | real: asserts RouteInfo.PluginID == golem15.fonoteka |
| test_jwt_group_contains_oauth_consent_and_connected_apps | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_jwt_group_contains_oauth_consent_and_connected_apps | real |
| test_code_or_token_producing_routes_do_not_carry_inv_scope | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_code_or_token_producing_routes_do_not_carry_inv_scope | real |
| test_token_surface_has_exactly_one_discogs_route | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_token_surface_has_exactly_one_discogs_route | deferred-scope: current count is 0, PHP's is 1; update once discogs ships |
| test_interactive_discogs_import_routes_stay_jwt_only | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_interactive_discogs_import_routes_stay_jwt_only | deferred-scope |
| test_no_route_on_the_token_prefix_is_bearerless | fonoteka.go | plugins/golem15/fonoteka | TestOAuthTokenSurfaceIsolationCoverage | test_no_route_on_the_token_prefix_is_bearerless | real |