Skip to content

Remove social runtime surfaces (ORB-233) - #787

Merged
thomasluizon merged 3 commits into
mainfrom
thomasluizon/ticket-239-social-removal
Oct 19, 2026
Merged

thomasluizon merged 3 commits into
mainfrom
thomasluizon/ticket-239-social-removal

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner

Removes the social API runtime for ORB-233. Closes thomasluizon/orbit-tickets#239.

The branch started from the merged removal patterns in API PRs #779 and #783. This follows the final work-order instructions: retain schema, installed-client fields, historical badges, and user-owned data for their later release barriers.

Changes and approach

  • Delete FriendsController, PublicProfileController, all 30 files under Orbit.Application/Social, the three social profile commands/actions and validators, public-profile queries/builders, social repository readers, and their registrations/tests.
  • Remove 16 HTTP operations across 15 paths, one capability (social.manage), one advertised scope (manage_social), nine rate policies, and both feed-emission call sites. Tree inspection found zero social chat tools, MCP tools, pay gates, background jobs, or health entries to remove. Existing notification privacy handling remains necessary for stored messages.
  • Inject push delivery directly into GamificationService, remove the feed dependency from UserStreakService, and remove the feed-only milestone constant. Habit logging, streak computation, XP, achievement awards and push delivery retain their existing behavior.
  • Stop default-handle generation in signup and staging seeding. Concurrent signup, OAuth and email provisioning tests now assert null handles while still checking session creation and uniform work order. This does not claim to close ORB-96 (thomasluizon/orbit-tickets#102).
  • Regenerate both OpenAPI documents with dotnet build. Every surviving route definition is structurally identical. ProfileResponse retains its property names, types and required set; only compatibility documentation and social deprecation markers change.
  • Remove obsolete error/validation constants, two suppression-allowlist entries for deleted files, a deleted-file duplication exclusion, and stale documentation. No harness logic, new suppression, or deprecation attribute is added.

Compatibility and retained data

ProfileResponse.handle (string?) returns null, socialOptIn (bool) returns false, and publicProfile (PublicProfileSettings?) returns null. PublicProfileSettings retains enabled, slug, shareUrl, showStreak, showLevel, showAchievements, and showTopHabits with their existing types; its record moves into Profile/Models with its original namespace. The contraction belongs to thomasluizon/orbit-tickets#685 after the carrying client release and MinSupportedVersion gate.

The five entity types, tables, DbSets, mappings, indexes and seven Users properties remain: Handle, SocialOptIn, PublicProfileSlug, PublicProfileShowStreak, PublicProfileShowLevel, PublicProfileShowAchievements, PublicProfileShowTopHabits. DomainConstants.HandleMaxLength remains because the mapping uses it. The retained types are Friendship, Cheer, BlockedUser, Report, and FriendFeedEvent; they support schema mapping, data export/reset, and tests for persisted data. Their enums and domain guards also remain. No migration or snapshot changes are included; the existing pending-model-change assertion passes.

Social rows may still be owned by users. ExportUserDataQuery, its five exported social collections, and AccountResetRepository keep handling them. This PR does not claim to close the table-dependent defect in ORB-97 (thomasluizon/orbit-tickets#103); its subject remains until the later table drop.

The four retired definitions first_cheer, first_friend, squad_goals, and cheerleader stay resolvable with IsRetired: true, preserving earned badges and XP. Their translations and AchievementCategory.Social remain needed. show_off, year_in_review, referral and milestone sharing remain available.

IContentModerationService, ContentModerationService, and the HTTP-client DI registration survive. The interface has a URL-linked WHY note for ORB-11 (thomasluizon/orbit-tickets#17), and its registration test resolves the real implementation.

Rollback of this code removal can reuse the preserved schema and rows. The later drop in thomasluizon/orbit-tickets#1555 is destructive: its rollback recreates schema, not erased data.

Stored scope validation

ManageSocial is deleted. Stored scopes are accepted without checking AgentScopes.All; the only use of that set is the new-key validator in CreateApiKeyValidator. ApiKeyAuthenticationHandler transfers the stored list directly:

claims.AddRange(candidate.Scopes.Select(scope => new Claim("scope", scope)));

AgentOperationExecutor.GetGrantedScopes returns API-key scopes unchanged:

if (request.AuthMethod == AgentAuthMethod.ApiKey)
    return request.GrantedScopes ?? [];

AgentPolicyEvaluator checks the requested capability's scope:

if (context.AuthMethod == AgentAuthMethod.ApiKey &&
    !context.GrantedScopes.Contains(capability.Scope, StringComparer.OrdinalIgnoreCase))

OAuth issues AgentScopes.ClaudeDefaultScopes, which did not contain manage_social. The regression test creates a real API key with both manage_social and read_habits, authenticates it through the production handler, and proves the surviving scope still reaches claims. No existing token data is rewritten. The removed scope has no catalog capability to grant. This change introduces no new external response-field reads.

Test evidence

Before removal, unchanged infrastructure tests passed:

dotnet test tests/Orbit.Infrastructure.Tests --filter 'FullyQualifiedName~SocialDeprecationTests|FullyQualifiedName~ContentModerationRegistrationTests|FullyQualifiedName~UserStreakServiceTests'

Observed: exit 0, 67 passed, zero skipped. After strengthening SocialDeprecationTests to require absent routes/controllers/capabilities and compatible fields without deprecation, this command failed before implementation:

dotnet test tests/Orbit.Infrastructure.Tests --filter 'FullyQualifiedName~SocialDeprecationTests'

Observed: exit 1, 35 failed and 13 passed because the runtime routes/controllers and deprecation markers still existed. The same cases pass after removal.

The new profile test also failed before implementation:

dotnet test tests/Orbit.Application.Tests --filter 'FullyQualifiedName~Handle_LegacySocialSettings_ReturnsNeutralCompatibilityFields'

Observed: exit 1; the serialized handle was a string rather than null. After implementation it passes, including checks that stored legacy values remain intact. Focused application tests passed 177 cases; focused infrastructure tests passed 121 cases. Signup follow-up tests passed 103 infrastructure and 67 gamification cases.

Final verification on the committed branch:

Command Result
dotnet build Orbit.slnx Exit 0, zero errors, 19 pre-existing warnings
dotnet test tests/Orbit.Domain.Tests Exit 0, 729 passed, zero skipped
dotnet test tests/Orbit.Application.Tests Exit 0, 5,148 passed, zero skipped
dotnet test tests/Orbit.Infrastructure.Tests Exit 0, 3,722 passed, zero skipped
dotnet test tests/Orbit.Analyzers.Tests Exit 0, 32 passed, zero skipped

All 9,631 tests pass. The warning-free expectation is not met by the existing package graph and unchanged files: NU1608 package constraints, Firebase Message.Token, API-versioning diagnostics, the retired ad-reward action tests, and an existing captured constructor parameter. No warning points at changed code. These warnings were not suppressed or addressed outside this removal's scope.

Local convention checks pass: timeless prose, dash ban, suppression allowlist, diff whitespace, no new pragma/SuppressMessage, and URL-linked bare-comment inspection. Browser/server and live-database checks were not run under this work order; removed routes are checked by controller reflection and both generated contracts. Schema continuity is checked by the existing EF model test.

Reference sweep

Files-only case-insensitive sweep across src/ and tests/, excluding unchanged migration history and generated contracts (checked separately). MediatR Handle(...) methods are excluded; method-group references and generic uses of report/friendly remain incidental matches. Survivors are preserved storage/export/reset, historical badge definitions/translations, compatibility DTOs and their tests, referral copy, notification privacy, and unrelated reporting/handler terminology.

rg --sort path -i -l --pcre2 'friend|cheer|blockeduser|socialoptin|publicprofile|\b(?:Report|Reports|ExportedReport|ReporterId|ReportedUserId)\b|\.Handle\b(?!\s*\()|Handle(?:Taken|Format|MinLength|MaxLength)|set-handle' src tests -g '!**/Migrations/**' -g '!openapi*.json'
src/Orbit.Api/Controllers/AchievementsController.cs
src/Orbit.Api/Extensions/ServiceCollectionExtensions.cs
src/Orbit.Api/Extensions/WebApplicationExtensions.cs
src/Orbit.Api/Mcp/Tools/McpInputParser.cs
src/Orbit.Application/Chat/ChatIntentRouter.cs
src/Orbit.Application/Chat/ChatToolGroups.cs
src/Orbit.Application/Chat/Tools/Implementations/BulkDeleteHabitsTool.cs
src/Orbit.Application/Chat/Tools/Implementations/BulkLogHabitsTool.cs
src/Orbit.Application/Chat/Tools/Implementations/BulkSkipHabitsTool.cs
src/Orbit.Application/Chat/Tools/Implementations/BulkUpdateHabitEmojisTool.cs
src/Orbit.Application/Common/ErrorCopy.cs
src/Orbit.Application/Common/LocaleHelper.cs
src/Orbit.Application/Common/PlaySubscriptionStateExtensions.cs
src/Orbit.Application/Gamification/AchievementDefinitions.cs
src/Orbit.Application/Gamification/AchievementEventMap.cs
src/Orbit.Application/Gamification/AchievementProgressCalculator.cs
src/Orbit.Application/Gamification/Queries/GetXpHistoryQuery.cs
src/Orbit.Application/Goals/Services/GoalStreakSyncService.cs
src/Orbit.Application/Profile/Models/PublicProfileSettings.cs
src/Orbit.Application/Profile/Models/UserDataExport.cs
src/Orbit.Application/Profile/Queries/ExportUserDataQuery.cs
src/Orbit.Application/Profile/Queries/GetProfileQuery.cs
src/Orbit.Application/Referrals/Commands/CheckReferralCompletionCommand.cs
src/Orbit.Domain/Common/DomainConstants.cs
src/Orbit.Domain/Common/DomainErrors.cs
src/Orbit.Domain/Entities/BlockedUser.cs
src/Orbit.Domain/Entities/Challenge.cs
src/Orbit.Domain/Entities/Cheer.cs
src/Orbit.Domain/Entities/FriendFeedEvent.cs
src/Orbit.Domain/Entities/Friendship.cs
src/Orbit.Domain/Entities/Goal.cs
src/Orbit.Domain/Entities/Report.cs
src/Orbit.Domain/Entities/User.cs
src/Orbit.Domain/Enums/FriendFeedEventType.cs
src/Orbit.Domain/Enums/FriendshipStatus.cs
src/Orbit.Domain/Interfaces/IAgentPlatformServices.cs
src/Orbit.Domain/Models/AgentChatWriteHold.cs
src/Orbit.Infrastructure/Persistence/AccountResetRepository.cs
src/Orbit.Infrastructure/Persistence/AuthUserStore.cs
src/Orbit.Infrastructure/Persistence/OrbitDbContext.cs
src/Orbit.Infrastructure/Services/AiSummaryService.cs
src/Orbit.Infrastructure/Services/AppConfigService.cs
src/Orbit.Infrastructure/Services/DatabaseHealthCheck.cs
src/Orbit.Infrastructure/Services/GoogleCalendarEventFetcher.cs
src/Orbit.Infrastructure/Services/Prompts/Sections/Static/GlobalRulesSection.cs
tests/CLAUDE.md
tests/Orbit.Application.Tests/Commands/Auth/AuthRegistrationWorkTests.cs
tests/Orbit.Application.Tests/Commands/Auth/AuthSignupDispatchTests.cs
tests/Orbit.Application.Tests/Commands/Auth/CompleteSignupJobTests.cs
tests/Orbit.Application.Tests/Commands/Auth/GoogleCodeAuthCommandHandlerTests.cs
tests/Orbit.Application.Tests/Commands/Auth/VerifyCodeCommandHandlerTests.cs
tests/Orbit.Application.Tests/Commands/Support/SendSupportCommandHandlerTests.cs
tests/Orbit.Application.Tests/Gamification/AchievementDefinitionsTests.cs
tests/Orbit.Application.Tests/Gamification/ReportEventCommandValidatorTests.cs
tests/Orbit.Application.Tests/Queries/Gamification/GetAchievementsQueryHandlerTests.cs
tests/Orbit.Application.Tests/Queries/Gamification/GetGamificationProfileQueryHandlerTests.cs
tests/Orbit.Application.Tests/Queries/Profile/ExportUserDataQueryHandlerTests.cs
tests/Orbit.Application.Tests/Queries/Profile/GetProfileQueryHandlerTests.cs
tests/Orbit.Application.Tests/Validators/SendSupportCommandValidatorTests.cs
tests/Orbit.Domain.Tests/Entities/SocialEntitiesTests.cs
tests/Orbit.Domain.Tests/Entities/UserSignupTests.cs
tests/Orbit.Infrastructure.Tests/AI/AiIntentServiceStreamingTests.cs
tests/Orbit.Infrastructure.Tests/Compatibility/README.md
tests/Orbit.Infrastructure.Tests/Controllers/ApiVersioningTests.cs
tests/Orbit.Infrastructure.Tests/Controllers/AuthControllerTests.cs
tests/Orbit.Infrastructure.Tests/Controllers/OAuthControllerTests.cs
tests/Orbit.Infrastructure.Tests/Controllers/OAuthPageScriptTests.mjs
tests/Orbit.Infrastructure.Tests/Controllers/SocialDeprecationTests.cs
tests/Orbit.Infrastructure.Tests/Controllers/SupportControllerTests.cs
tests/Orbit.Infrastructure.Tests/Email/EmailTemplateRendererTests.cs
tests/Orbit.Infrastructure.Tests/Health/HealthCheckResponseTests.cs
tests/Orbit.Infrastructure.Tests/Mcp/NotificationToolsTests.cs
tests/Orbit.Infrastructure.Tests/Persistence/AccountResetRepositoryTests.cs
tests/Orbit.Infrastructure.Tests/Persistence/OrbitDbContextTests.cs
tests/Orbit.Infrastructure.Tests/Persistence/UserDeactivationQueryFilterTests.cs
tests/Orbit.Infrastructure.Tests/Services/AgentCatalogServiceTests.cs
tests/Orbit.Infrastructure.Tests/Services/AiSummaryServiceTests.cs
tests/Orbit.Infrastructure.Tests/Services/CompleteSignupReferralTests.cs
tests/Orbit.Infrastructure.Tests/Services/DistributedRateLimitServiceTests.cs
tests/Orbit.Infrastructure.Tests/Services/GoogleAuthFirstLoginRaceTests.cs
tests/Orbit.Infrastructure.Tests/Services/ReminderSchedulerServiceTests.cs
tests/Orbit.Infrastructure.Tests/Services/SesEmailServiceTests.cs
tests/Orbit.Infrastructure.Tests/Services/SignupJobDispatcherTests.cs

Removed runtime-symbol sweep:

rg -n 'FriendGraphService|SocialAccessGuard|SocialInteractionServices|SocialNotificationDispatcher|FriendFeedEmitter|IFriendFeedEventEmitter|IFriendFeedReader|ISocialGraphReader|SetHandleCommand|SetSocialOptInCommand|UpdatePublicProfileCommand|GetPublicProfileQuery|GetFriendProfileQuery|SocialCapabilities|ManageSocial|SocialManage|StreakMilestoneTiers' src -g '!**/Migrations/**' -g '!openapi*.json'

Observed: no output, exit 1 (no matches).

Assumptions

  • Exclude src/Orbit.Application/Profile/Models/PublicProfileSettings.cs from SonarCloud coverage: after the removal nothing builds the record, it holds no logic, and the committed openapi.json snapshot plus the OpenAPI Breaking-Change Gate hold its shape; Carry main fixes into redesign main (#746) #685 deletes the record and this exclusion together (rejected alternative: a test that only constructs the record to read its getters).
  • Apply the final orchestrator notes to conflicting earlier acceptance criteria (rejected alternative: dropping schema, DTO fields and retired badges in this PR).
  • Keep PublicProfileSettings in its original namespace when separating its compatibility record from the deleted command (rejected alternative: deleting or changing the response type).
  • Keep social export/reset paths because user-owned rows have not been proven absent (rejected alternative: assuming deprecation drained those tables).

Manual steps

  • Merging to main deploys nothing. The owner must approve the production API release. In GitHub Actions, run Release API (.github/workflows/release.yml) from main with inputs environment=production and branch=main. A successful Verify API health and live commit step proves the carrying commit is live.
  • The table/column drop belongs to thomasluizon/orbit-tickets#1555 in a later PR and release. Before contraction, record the compatible commit deployed to every production web instance and worker, plus deactivation and drain of incompatible instances and in-flight/queued work, following tests/Orbit.Infrastructure.Tests/Persistence/RollingMigrations.md.

pullfrog[bot]
pullfrog Bot previously approved these changes Oct 19, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed the complete social-runtime removal, its surviving application paths, and compatibility with the orbit-ui-mobile consumer.

  • Runtime removal: Deletes social controllers, profile actions, handlers, validators, graph/feed services, and their registrations and OpenAPI operations.
  • Compatibility and storage: Retains profile response shapes, persisted social data, export/reset handling, and historical achievement definitions while returning neutral social profile values.
  • Core behavior: Removes feed emission from gamification and streak processing, preserves push delivery, and stops generating handles during signup.
  • Agent access: Removes the social capability and advertised scope without invalidating existing API keys that also grant surviving scopes.
  • Verification: All 341 focused tests passed, covering removed routes, profile compatibility, signup, gamification, stored scopes, data export/reset, and EF model continuity. Cross-repository tracing found no current runtime consumer failure from the neutral profile values; the full test suite and live fleet rollout were not independently rerun or verified.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

The record is never built after the social removal; it stays only so the
profile response schema keeps its shape for old clients until #685, and the
committed OpenAPI snapshot holds that shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed b493869b against the previously reviewed 29635505, with the full PR diff as context.

  • Excluded the compatibility record from coverage: Added a file-specific SonarCloud coverage exclusion for PublicProfileSettings.cs, which contains only the retained response-shape record. The change leaves runtime behavior, contracts, general analysis exclusions, and build/test commands unchanged.

Verification was static; tests and live SonarCloud analysis were not rerun for this coverage-only change.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@sonarqubecloud

Copy link
Copy Markdown

@thomasluizon
thomasluizon merged commit 7c79309 into main Oct 19, 2026
25 checks passed
@thomasluizon
thomasluizon deleted the thomasluizon/ticket-239-social-removal branch October 19, 2026 16:42
thomasluizon added a commit that referenced this pull request Oct 19, 2026
…EADME (#746) (#790)

* Remove social runtime surfaces (ORB-233) (#787)

* Remove social runtime surfaces (ORB-233)

* Finish social signup assertions and reference cleanup

* ci: exclude the retained public profile shape from coverage

The record is never built after the social removal; it stays only so the
profile response schema keeps its shape for old clients until #685, and the
committed OpenAPI snapshot holds that shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 7c79309)

* docs: point the grounding mode switch at the Render database (#789)

Production data lives on Render Postgres; the Supabase project is deleted.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 3330b8c)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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