Skip to content

Dedup - #12

Merged
Azyyyyyy merged 92 commits into
developfrom
dedup
Jul 21, 2026
Merged

Dedup#12
Azyyyyyy merged 92 commits into
developfrom
dedup

Conversation

@Azyyyyyy

Copy link
Copy Markdown
Owner

No description provided.

Azyyyyyy added 2 commits July 18, 2026 00:48
- Introduced InMemoryAlterRepositoryTests to ensure direct repository coverage for alter visibility behavior.
- Implemented tests for various visibility levels (Public, Friends Only, Trusted Only, Private) to validate filtering based on viewer friendship levels.
- Added helper methods for seeding friendships and creating alters to facilitate comprehensive testing.
- Consolidated visibility logic checks to ensure consistency with existing controller tests, addressing potential regression issues.

This commit enhances the test suite by closing the gap in repository-level testing for the InMemory backend, ensuring robust coverage for visibility-related functionality.
@Azyyyyyy
Azyyyyyy changed the base branch from main to develop July 18, 2026 12:26
Comment thread csharp/RefactorTool/Program.cs Outdated
Azyyyyyy and others added 20 commits July 18, 2026 21:43
DeleteFrontByIdAsync cleared any active front on the alter when the front
being deleted was found in history, regardless of whether the active front
was the same one. This caused a subsequent active front (F2) to be wiped
when the predecessor (F1) was deleted from history.

Fix: mirror Scylla's guard — only clear the active entry when its FrontId
matches the front being deleted.

Adds fronting-delete-parity.trace.json to ReplayParityTests to cover the
scenario: start F1, end F1, start F2, delete F1 => F2 must remain active.
…writers [R2-A2]

UpdateAlterAsync, DeleteAlterAsync, SetAlterLockedAsync, SetAlterPinnedAsync
wrapped their bodies in DatabaseTransientRetry.ExecuteScyllaAsync and then
called GetAlterRefAsync which itself uses _scopeResolver.ExecuteAsync (another
retry envelope). Transient errors would retry 5x5=25 times.

Fix: rewrite all four methods to use _scopeResolver.ExecuteAsync directly,
with a private GetAlterRefCoreAsync(ScyllaScope, EntryId, ct) that reads
the ref within the already-open scope — eliminating the nested envelope.
…rtJobRunner [R2-A3]

Round 1 left PkImportJobRunner returning ImportFailed. The plan wording called
for ImportErrorCode.Unimplemented to distinguish 'this importer is not built
yet' from 'a real importer ran and returned a graceful failure'.

Decision: add Unimplemented (wire: 'unimplemented') to ImportErrorCode and
switch the stub runner. ImportFailed retains its 'generic fallback for runners
that failed without a specific code' meaning.
…t sites [R2-B1]

Creates TestClient.NoRedirect(IWebFactoryFixture) and NoRedirect(InterfoldWebApplicationFactory)
to eliminate the 42 identical new WebApplicationFactoryClientOptions { AllowAutoRedirect = false }
blocks across 14 test files.

Also bundles D13:
- Add SendAuthedDeleteAsync to TestJson
- Sweep 4 raw HttpRequestMessage(HttpMethod.Delete) sites
- Fix AlterJournalsControllerTests:17 empty-options quirk (inconsistent with all siblings,
  normalised to AllowAutoRedirect = false)
…9 handler sites [R2-B3]

Sweeps 19 'TryGetSystemTopic' guards across the event handlers in
Alter, Fronting, Import, Journal, Poll, Settings, Tag, and Friendship
socket handler classes to use the unified SendIfJoinedAsync helper.
… sweep 9 controllers [R2-B2]

Introduces DispatchNoContentAsync, DispatchAcceptedAsync, and DispatchCreatedAsync
helpers on the base controller, centralising command envelope building,
handling, and response mapping.

Sweeps ~54 endpoints across all 9 controllers (excluding AuthController) to
use the unified dispatchers, making their bodies cleaner and reducing boilerplate.
…sweep 22 sites [R2-B4]

Adds ExecuteGlobalAsync overloads to IScyllaScopeResolver to allow executing
global (non-regional) queries with transient retry policy.

Sweeps 22 DatabaseTransientRetry sites onto the scope resolver:
- 12 global sites in ScyllaFriendshipRepository
- 3 global sites in ScyllaNotificationTokenRepository
- 7 regional/global sites in ScyllaImportOperationRepository
Extracts MapAlterReadModel to AlterRowMappers in Scylla infrastructure,
replacing 2 duplicate mapping expressions inside ScyllaAlterRepository.

Also extracts private MapAlterReadModel helper to InMemoryAlterRepository
as a mirror to remove 2 duplicate mappings in the in-memory driver.
…del [R2-B5-b]

Extracts MapFrontHistoryReadModel to a new FrontingRowMappers class,
replacing 4 duplicate mapping statements in ScyllaFrontingRepository.
Extracts MapAlterJournalReadModel and MapJournalReadModel to a new
JournalRowMappers class, replacing 4 duplicate mapping statements
inside ScyllaJournalRepository.

Also extracts private MapAlterJournalReadModel and MapJournalReadModel
mirrors to InMemoryJournalRepository to clean up 4 duplicate mappings
in the in-memory driver.
Extracts MapTagReadModel and MapTagPublicReadModel to TagRowMappers
class, replacing 4 duplicate mapping statements inside ScyllaTagRepository.

Also extracts private MapTagReadModel and MapTagPublicReadModel mirrors
to InMemoryTagRepository to clean up 4 duplicate mappings in the
in-memory driver.
… sites [R2-C1]

Round 2 wave C, item 1. The `BootstrapAsync` / `PublishAsync` helpers added in
Round 1 cover the "top of test body: fresh scratch + primary bootstrap/publish"
shape, but the DinD suite has dozens of *secondary* subcommand invocations
(`install-service`, `update-images`, `backup`, `restore`, `rotate-secrets`,
`rotate-certs`, second `bootstrap`, etc.) against an existing scratch that were
still hand-rolling the same six-item arg list per site.

Add `DinDFixtureBase.RunOnScratchAsync(scratch, testName, command, extraArgs)`
which pre-populates `--config`, `--output-dir`, `--non-interactive` from the
scratch and appends the caller's extra flags. It deliberately does NOT assert
exit code so callers keep flexibility for the exit-non-zero cases
(HealthTimeoutDumpsComposeLogs, RestoreWithoutArchivesFailsClearly,
BackupWithoutComposeFailsClearly, UnsupportedOsTests, etc.).

Sweeps applied:
  SystemdInstallTests            7 sites (all install-service invocations)
  RestorePhaseTests              6 sites (backup / restore combos)
  BackupPhaseTests               5 sites (backup + retention loop + misuse)
  UbuntuBootstrapTests           5 sites (rotate-secrets, rotate-certs,
                                          IsIdempotentOnRerun,
                                          RecoversFromInterruptedPublish)
  BootstrapIdempotenceTests      4 sites (bootstrap re-run pairs)
  UpdateImagesPhaseTests         4 sites (update-images + misuse)
  LaunchPhaseTests               2 sites (HealthTimeout, RespectsCustomApiHttpPort)
  UpdateImagesCassandraModeTests 2 sites (cassandra-mode update-images)
  DbInitFaultRecoveryTests       2 sites (fault-inject halt + resume)
  MdnsGateTests                  1 site
  UnsupportedOsTests             1 site
  UbuntuBootstrapTests           2 sites  PublishAsync sweep (single-shot pubs)
  TrustStoreFalseTests           1 site   PublishAsync sweep

The `up` subcommand invocation in LaunchPhaseTests deliberately omits --config
(it operates on the pre-published output dir only) and stays on the raw
RunBootstrapperAsync path; the four PrereqsPhaseTests sites also intentionally
omit --config/--output-dir to exercise the no-config path.

Also folds in two pre-migrated sites (TrustDownloadTests, WebHttpsTests) that
already used BootstrapAsync/PublishAsync from a prior working session -- they're
the same pattern of work.

15 files touched, +136 / -192 (net -56 LOC).

Co-authored-by: Cursor <cursoragent@cursor.com>
Update the round-2 dedup plan to reflect that C1 shipped as commit d863855
under a broader scope than originally spec'd. The bullet's `~59 sites onto
BootstrapAsync` framing was based on the raw `RunBootstrapperAsync` mention
count; the actual sweep-able set was 3 sites for `BootstrapAsync`/`PublishAsync`
plus ~40 sites once a second helper (`RunOnScratchAsync`) was added to cover
secondary subcommand invocations against an existing scratch.

The full progress banner now lists C1 in the completed set (16 commits, was 15).

Co-authored-by: Cursor <cursoragent@cursor.com>
…dentifier generics [R2-C2]

Round-2 C2 closes the B7 tail on the InMemory adapter: the three
FindOrCreateSystemIdBy{Discord,Email,Apple} bodies and the three
Unlink{Discord,Email,Apple}Async bodies were hand-copied six-way. All
six now dispatch to two generics keyed by the identity wrapper type +
a static extractor lambda, matching the shape B7 used for
LinkIdentifier<TIdentity>. DeleteAsync's identity cleanup also routes
through the new UnlinkIdentifier so the three-block copy inside Delete
collapses to three one-line calls.

Scylla side was already factored via UnlinkIdentityAsync(systemId,
ProviderColumn) in an earlier pass, so this bullet touches InMemory
only.

Adds InMemoryAccountRepositoryIdentityRegressionTests covering the
core refactor risk (dict-pair swap - UnlinkDiscord scrubbing the email
map, etc.) plus the round-trip / idempotency / case-insensitivity
invariants that had no direct unit coverage before this bullet. All 8
new tests pass; the 4 existing link-token regression tests still pass;
373/373 unit tests green overall.

Net -42 LOC on InMemoryAccountRepository.cs (79 ins, 121 del).

Co-authored-by: Cursor <cursoragent@cursor.com>
Azyyyyyy and others added 14 commits July 19, 2026 13:23
Add PsqlAsync and CqlshAsync to DinDFixtureBase so the 'docker compose -f {composeFile} exec -T [-e PGPASSWORD=...] msg-db psql -U ... -d ... -h ... {sql}' shape and the corresponding 'docker compose -f {composeFile} exec -T scylla cqlsh -u ... -p ... -e {cql} 2>&1 || true' shape land in one place. Password parameters are forwarded verbatim so literal values, $ADMIN_PW-style shell variables, and $(grep ...) subshells all keep working. Quoted SQL/CQL expressions are also passed verbatim so callers keep control of shell quoting.

Sweep 10 sites: DbInitSecurityInvariantsTests (2 cqlsh + 4 psql), DbInitFaultRecoveryTests (2 cqlsh + 1 psql), RestorePhaseTests (4 psql). RestorePhase pre-extracts the admin password once via a single ExecAsync + grep|sed instead of re-deriving ADMIN_PW=\ inside every compound sh -c. Drops one redundant 'using System.Text;' now that ParseEnv is gone from the test.

Co-authored-by: Cursor <cursoragent@cursor.com>
…sts body extract

B8: add BaseEndpointTest.SeedVisibilityQuartetAsync(client, prefix) that seeds the four viewer principals (owner + nonFriend + friend + trusted) with a public profile each and an alter on each non-owner (needed so the guarded reads have a row to gate). Deliberately unifies on the 'seed all four' shape that PublicSystemsControllerTests already used — AltersControllerTests had been seeding only the owner, which risked masking a test-side race where the friend-request accept resolves a viewer id with no profile row yet. Sweep 5 sites: 3 in PublicSystemsControllerTests, 2 in AltersControllerTests.

C1: with the setup lifted into the shared helper, the two AltersControllerTests methods FieldSecurityLevelByRelationship_AppliesCorrectly and CustomFields_FieldSecurityLevelByRelationship_AppliesCorrectly are byte-identical except for the client type (TestClient.NoRedirect vs fixture.Factory.CreateClient) and the principal prefix. Extract the 60-line shared body into a private static RunFieldVisibilityScenarioAsync(client, prefix) so the mirror pair keeps two entry points (pinning both codepaths) but only one copy of the assertion body. Also fixes the line-45 friend->nonFriend drift bug that existed before this refactor and would silently pass because the assertion set didn't distinguish the two viewers' expected slice.
Co-authored-by: Cursor <cursoragent@cursor.com>
…to DockerCompose

Add three shared builders to DockerCompose:
  * BuildPostgresExecArgs(composeFile, service, tool, adminUser, database, params trailer) — the 'compose -f X exec -T --env PGPASSWORD service tool -U user -d db {trailer}' preamble that pg_dump, pg_restore, and (future) pg_isready-with-creds all share. The password lands via --env so it never appears on argv, matching the security invariant asserted by BackupCommandBuildingTests.
  * BuildContainerCpFromContainer(id, path) — 'docker cp id:path -' (stdout stream).
  * BuildContainerCpIntoContainer(id, path) — 'docker cp - id:path' (stdin stream).

Retarget BackupPhase.BuildPostgresDumpArgs / BuildContainerCpArgs and RestorePhase.BuildPgRestoreArgs / BuildContainerCpWriteArgs as one-line delegators so the existing BackupCommandBuildingTests + RestoreCommandBuildingTests argv-shape assertions continue to pin the phase-level contract (all 20 tests still pass). The next phase that needs to exec postgres tools as admin (a future WaitForPostgresAsync variant, an ad-hoc DDL runner) picks up the shared preamble by construction rather than re-hand-rolling the auth-sensitive '--env PGPASSWORD' positioning.

Co-authored-by: Cursor <cursoragent@cursor.com>
The initial B3 landing used a bare 'string column' parameter on SetGlobalFlagAsync and SetAlterFlagAsync, which meant a future caller could still pass an arbitrary column identifier and slip a CQL-injection-adjacent literal into the interpolated UPDATE statement. The plan explicitly called for a closed 'JournalFlag' enum for exactly this reason - callers physically cannot pass anything other than Locked or Pinned.

Add a private nested 'JournalFlag' enum (Locked, Pinned) and a private static FlagToColumn(JournalFlag) mapper. Retarget both Set(Global|Alter)FlagAsync signatures onto the enum and update the four public entry points (SetGlobalLockedAsync, SetGlobalPinnedAsync, SetAlterLockedAsync, SetAlterPinnedAsync) to pass JournalFlag.Locked / JournalFlag.Pinned. FlagToColumn is the single place the enum-to-column-name mapping lives, and it throws ArgumentOutOfRangeException on any future enum variant that lacks a mapping so the next hand that adds JournalFlag.Archived (or similar) is forced to update the mapper in the same commit.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Refactored the SettingsController to utilize a new DispatchEncryptionKeyAsync method, reducing code duplication in the encryption setup and recovery processes.
- Updated FriendshipSocketEventHandlers to streamline friendship retrieval with a retry mechanism, improving readability and maintainability.
- Consolidated common logic in FrontingSocketEventHandlers and SettingsSocketEventHandlers for handling socket events, enhancing code clarity.
- Introduced a new UntilNotNullAsync method to handle eventual consistency in fetching friendship and friend request data, reducing boilerplate code across multiple handlers.
- Added FixedRegionContext to unit tests for consistent region handling in identity-related tests.

These changes aim to improve code organization and reduce redundancy across the codebase.
…ffects on missing polls

The new PollCommandFlow helper was introduced with hot Task/ValueTask
parameters, which C# evaluates eagerly. That meant _repo.UpdateAsync/
DeleteAsync and _bus.PublishAsync ran at the call site inside
ExecuteUpdateAsync/ExecuteDeleteAsync, BEFORE the ExistsAsync check
inside the helper.

Symptoms on a not-found row:
  * a spurious UPDATE/DELETE against the persistence adapter, and
  * a spurious PollUpdatedEvent / PollDeletedEvent on the cluster bus.

Both are invisible in the HTTP-level integration tests (the handler
still returns poll:not_found), which is exactly why the regression
slipped through. They corrupt downstream observers and can throw
unobserved exceptions in the returned-but-unawaited Task.

Fix: change ExecuteExistingPollMutationAsync's mutate/publish params
from Task<bool>/ValueTask to Func<CT, Task<bool>>/Func<CT, ValueTask>
so they're only invoked after the existence check passes, and
publishAccepted only fires on the accepted branch. Also adds a comment
at the seam explaining the trap for the next refactor.

Adds PollCommandFlowExecutionTests to lock the invariant in with
hand-rolled counting fakes:
  * DeletePoll_MissingPoll_DoesNotMutateOrPublish
  * DeletePoll_ExistsButMutationReturnsFalse_RejectsWithDeleteFailedAndDoesNotPublish
  * DeletePoll_HappyPath_CallsMutateOncePublishesOnceAndAccepts
  * UpdatePoll_MissingPoll_DoesNotMutateOrPublish

The Update and Delete branches share the helper; pinning them
separately guarantees drift in one branch cannot silently pass in the
other.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ueries -> 1)

The health check used to issue one `SELECT table_name FROM
system_schema.tables WHERE keyspace_name = ? AND table_name = ? LIMIT 1`
per required table, sequentially per keyspace. On the current schema
that is 20+ round-trips per health probe.

Replaces that loop with a single keyspace-scoped query and an
in-memory HashSet<string> lookup (OrdinalIgnoreCase for Cassandra's
case-insensitive table names). Behaviour is unchanged: the returned
list of missing tables is a subset of the input in the same order.

Also removes the pre-existing TODO that flagged this exact
optimisation.

Co-authored-by: Cursor <cursoragent@cursor.com>
…) helper

Each Scylla repository previously duplicated the same
ScyllaExistsQueries.RowExistsAsync(session, keyspace, "table", "id",
normalizedSystemId, id.Value) call at every existence check inside
ExistsAsync + UpdateAsync + DeleteAsync + related paths. That
constructed the same 6-arg call 2-3 times per repository, each
carrying the "which table + which id column" wiring inline.

Extracts a private static ExistsAsync(ScyllaScope, TId) helper on each
repository so the table + id-column encoding lives in one place, and
in-scope mutations reduce to `await ExistsAsync(scope, id)`. The
public ExistsAsync(SystemId, TId, CT) collapses to
_scopeResolver.ExecuteAsync(systemId, scope => ExistsAsync(scope, id),
ct).

Behaviour unchanged: same query, same params, same result. Just moves
the "table X keyed by column Y" wiring off every call site and into
one line per repository.

Co-authored-by: Cursor <cursoragent@cursor.com>
…repositories

Several InMemory repositories had the same
InMemoryStorageKeys.ForSystem(_regionContext, systemId) +
_bySystem.TryGetValue(systemKey, out var store) pattern repeated
across List / Get / Exists / Update / Delete / Relocate / etc. The
existing pattern in InMemorySettingsFieldRepository, InMemoryPoll,
InMemoryJournal, InMemoryTag already used private TryGetStore
helpers; this brings InMemoryAlterRepository (and refreshes the
others) into line so every store-lookup call site becomes:

    if (!TryGetStore(systemId, out var store)) return <empty>;

Also lifts a TryGetAlter/TryGetPoll/TryGetAlterEntry helper where the
same "resolve store then key into it" pair repeated. Behaviour
unchanged: same lock scope, same fallbacks, same friendship-level
resolution.

Co-authored-by: Cursor <cursoragent@cursor.com>
…malization helpers

Introduces per-aggregate flow helpers that centralise the recurring
"validate -> mutate -> check success -> publish -> return Success"
shape that every command handler in these aggregates was open-coding:

  * Alters/AlterCommandFlow.cs
  * Tags/TagCommandFlow.cs (+ TagCommandValidation.cs)
  * Fronting/FrontingCommandFlow.cs
  * Journals/GlobalJournalCommandFlow.cs
  * Journals/AlterJournalCommandFlow.cs
  * Friendships/FriendshipCommandFlow.cs
  * Friendships/FriendshipEventFlow.cs
  * Friendships/FriendshipCommandNormalization.cs

FriendshipEventFlow centralises the "publish A-side + publish B-side"
pair-event dance the 5 friendship handlers (Accept / Cancel / Reject /
Remove / Send / SetFriendTrust) were repeating with slightly different
ordering. FriendshipCommandNormalization encodes the "peer inherits
principal's region" invariant in one place instead of 10 call sites of
ScopedSystemId.Compose(principalId.Region, peer).

All parameter types that model deferred work (mutate/publish/apply)
are Func<CT, ...> rather than hot Task/ValueTask so nothing runs
before its guarded call point - matches the discipline restored on
PollCommandFlow in the preceding fix commit.

Handler bodies collapse from ~30-40 lines of open-coded logic to a
single delegating call each.

Co-authored-by: Cursor <cursoragent@cursor.com>
…+ inline AuthToken wrappers + tidy misc auth helpers

Three related tidies that all sit at the domain / api boundary:

1. Settings namespace consolidation
   - Move SettingsCommandHelper from Interfold.Domain into
     Interfold.Domain.Settings so all three sibling helpers
     (SettingsCommandHelper, SettingsIdempotentCommandFlow,
     SettingsFieldCommandFlow) live in the same namespace. Also
     move the physical file into the matching folder.
   - Introduce the two lighter helpers alongside the existing
     full-fat SettingsCommandHelper:
       * SettingsIdempotentCommandFlow - lightweight mutate/publish
         body for handlers that already inherit
         IdempotentCommandHandler (the base handles idempotency).
       * SettingsFieldCommandFlow - dedicated shape for the
         SettingsFieldCommandResult path (result carries FieldId).
   - Add an XML-doc "type-choice table" on SettingsCommandHelper
     that resolves the drift risk: a reader landing on any of the
     three sees the discovery rule for picking between them.
   - Adopt SettingsCommandHelper.PublishProfileUpdatedAsync at
     UpdateUsernameCommandHandler (was constructing the event by
     hand). Add the required `using Interfold.Domain.Settings;` to
     Accounts + Fronting call sites that live outside the Settings
     namespace. (The Fronting `using` addition rode along with the
     preceding FrontingCommandFlow commit for the same file - it
     became load-bearing here after the namespace move.)

2. Auth-token wrapper inlined
   - Delete AuthTokenCommandFlow (a 2-line wrapper around
     `await x; return Success(y);` with only 2 callers) and inline
     the body in RecordAuthTokenCommandHandler /
     RevokeAuthTokenCommandHandler. At two call sites the helper
     hurt readability more than it helped.

3. Misc auth tidy
   - AuthenticateOAuthCommandHandler / LinkOAuthIdentityCommandHandler:
     replace the inline `CommandExecutionResult.Rejected(new ConflictResult(...))`
     construction with the newer CommandHandler.RejectInvariant<T>()
     helper for consistency with other handlers in the codebase.
   - AuthController / OAuthControllerBase: extract the shared
     "OAuth identity failure" 403 response as
     OAuthControllerBase.OAuthIdentityFailureResponse() so the
     message string lives in one place.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ge and delete RefactorTool

Three IntegrationTests files were previously TODO stubs
(`//TODO: MAKE`); this fills them out with real coverage:

  * AuthLinkControllerTests - Begin missing-redirect-uri 400, valid
    Begin round-trip, unknown-provider handling, etc.
  * FriendRequestsControllerTests - request send / list / cancel /
    accept / reject / duplicate suppression, principal isolation.
  * FriendsControllerTests - list / trust-set / trust-unset / remove
    happy paths + rejection edges.

Net +345 / -6. All three files continue to use the standard
InMemoryWebFactoryFixture + ScyllaWebFactoryFixture +
CassandraWebFactoryFixture triple so the same tests run against every
persistence adapter.

Also deletes the one-off csharp/RefactorTool project (Program.cs +
RefactorTool.csproj). Its jobs were completed by the recent
deduplication rounds and it is no longer referenced from
Interfold.slnx or any build path.

Co-authored-by: Cursor <cursoragent@cursor.com>
…on methods

Move the 15 pure "publish a well-known event tuple" helpers off their static
containers and onto IClusterEventBus as extension methods, so command-handler
bodies read as `_eventBus.PublishFriendshipAddedBothWaysAsync(from, to, ct)`
instead of `FriendshipEventFlow.PublishFriendshipAddedBothWaysAsync(_eventBus,
from, to, ct)`. The noun the caller cares about (the bus) sits at the front
and the leading `_eventBus,` argument disappears from every call site.

Splits by aggregate:

- Interfold.Domain.Settings.SettingsEventBusExtensions
  · PublishProfileUpdatedAsync (moved out of SettingsCommandHelper)

- Interfold.Domain.Friendships.FriendshipEventBusExtensions
  · Publish{Friendship{Added,Removed}BothWays,
            Request{RemovedFromThenTo,RemovedToThenFrom}}Async
  · FriendshipEventFlow deleted — every method moved

- Interfold.Domain.Fronting.FrontingEventBusExtensions
  · PublishStateChangedAsync + 6 "…And…" transition variants
    (Started/Ended/Set/BulkUpdated/CommentUpdated/PrimaryChanged)
  · PublishDeletedAsync, PublishEndedForAltersAsync,
    PublishPrimaryClearedIfNeededAsync
  · Removed from FrontingCommandFlow — that class now holds only orchestration
    (validation, mutation-or-reject, front-by-id resolution, alter-fanout);
    Interfold.Contracts.Events using no longer needed there.

Call-site refactor across 17 handlers:
  · 5 Settings: DeleteAvatar, SetupEncryption, UpdateDescription, UploadAvatar,
    plus SetPrimaryFront + UpdateUsername
  · 5 Friendships: Accept, Cancel, Reject, Remove, Send
  · 7 Fronting: BulkUpdate, DeleteFrontById, EndFront, SetFront,
    SetPrimaryFront, StartFront, UpdateFrontComment

Same-assembly extension resolution — every caller lives in Interfold.Domain
and either shares the extension's namespace or already has the appropriate
`using` (UpdateUsernameCommandHandler and SetPrimaryFrontCommandHandler both
already have `using Interfold.Domain.Settings;` from prior commits).

Verified: full solution build clean (0 errors), Interfold.Api.UnitTests 377/377
passing, Interfold.Bootstrapper.UnitTests 382 passing + 1 Unix-only skip.

Co-authored-by: Cursor <cursoragent@cursor.com>
Consolidates Round 6 and Round 7 dedup sweeps, fixes three clusters of
pre-existing CI failures uncovered by the sweeps, and closes with a small
QoL pass on InterfoldWebApplicationFactory so tests read the persistence
mode off the shared enum instead of round-tripping magic strings.

Round 6 — dedup

- Contracts: extract StringBackedJsonConverter<T> base and fold 8 JSON
  converters (AvatarUrl, EncryptionMaterial, EntityRef, ErrorCode,
  IdempotencyKey, IdentityWrappers, OperationId, PollData.Question,
  SystemId) onto it. Wire-format contract preserved — WireByteFreezeTests
  still green.
- Scylla: delete the standalone ApplySchema method on ScyllaMigrationService
  and route its single caller through ApplyTemplatedMigrationPerKeyspace
  with SchemaMigration.
- Bootstrapper tests: replace the last four `grep | sed` secrets-JSON
  extractions in DbInitSecurityInvariantsTests.cs and
  DbInitFaultRecoveryTests.cs with dinD.ReadSecretsFieldAsync so the
  helper is the single source of truth for that shape.
- Bootstrapper Aspire: introduce
  PublishPhase.EnumerateSharedAspireParameters as the single source of
  truth for the 24 shared Aspire params, seeded into both BuildEnvReplacements
  (kebab-case .env) and PublishInProcessAsync (upper-snake-case in-memory
  config). New unit test in PublishEnvPostProcessingTests pins both the
  count and the kebab→upper-snake mapping.

Round 7 — duplicate-type sweep

- Delete Interfold.Domain.Abstractions.SpImportResult and re-type
  ISimplyPluralImportService.ImportAsync to return
  Interfold.Domain.Abstractions.ImportJobs.ImportJobOutcome directly.
  SpImportJobRunner.RunAsync is now a pure pass-through; the terminal-state
  contract (graceful failures must populate ErrorCode, throws classify as
  `exception`) lives on the service, not translated at the runner boundary.
  Callers in SimplyPluralImportService (ImportAsync + ValidateEncryptionKeyAsync)
  and the SpImportTests helper updated. Verified with SpImportTests
  (23/23) and ImportJobBackgroundServiceTests (5/5).
- Delete the private nested FixedRegionContext in
  InMemoryAlterRepositoryTests and adopt the shared Support/FixedRegionContext
  helper. Verified with InMemoryAlterRepositoryTests (5/5).

CI fixes uncovered by the sweep

- AuthLinkController.cs: two independent fixes.
  · Begin: add up-front redirect_uri guard returning 400 MissingRedirectUri
    (was landing on the challenge-issue 400 branch after cookie writes had
    already happened, tripping the documented contract).
  · Callback: this route is [AllowAnonymous], so BuildEnvelope's PrincipalId
    lookup throws InvalidOperationException before the handler ever runs.
    Mirror AuthController.Callback and hand-build the CommandEnvelope with
    a synthetic `nam:auth` principal — the LinkOAuthIdentityCommand handler
    resolves the real system id off the link token itself, so command
    PrincipalId is never observed.
- AuthLinkControllerTests.cs: root-cause was WebApplicationFactory<Program>
  handing back different IServiceProvider trees for `Factory.Services` vs
  an HTTP request scope, so the direct-repo seed wrote to a different
  InMemory dictionary than the callback read from. Move both flow tests
  onto per-test private factories pinned to NodeGroup=Primary, and seed
  the link token via GET /api/settings/link_token (Primary-only write
  path) so seed and callback share one SP.
- DinDFixtureBase.CountFilesAsync: change the signature from
  `(string globExpr)` to `(DinDScratch scratch, string relativePathOrGlob)`
  so callers can no longer forget the `$` on `"{scratch.OutputDir}/…"` (that
  bug had five instances across BackupPhaseTests and UpdateImagesPhaseTests
  which had been shipping since the previous CI green). Sweep updates all
  ten call sites to pass the scratch as a first-class arg.
- UnsupportedOsTests.cs: the "no partial artifacts" assertion was comparing
  an ExecResult against `0` instead of parsing the wc -l stdout. Parse the
  stdout to int and assert on that.

QoL — typed persistence mode on InterfoldWebApplicationFactory

- Change the InterfoldWebApplicationFactory ctor from `string persistenceType`
  to `PersistenceMode persistenceMode`. The wire spelling is produced inside
  the ctor via EnumWireExtensions.ToWire<TEnum> — the same single source of
  truth every other Interfold enum uses. Expose a public
  `PersistenceMode PersistenceMode { get; }` for tests that need to layer
  extra config onto a sibling factory. Internal `_persistenceType == "inmemory"`
  string comparisons fold to `PersistenceMode != PersistenceMode.InMemory`.
- Update the 3 fixtures (InMemory / Scylla / Cassandra) and 3 controller
  tests (ClusterRoleAndOAuthRegistrationTests, InMemorySecretsSeedTests,
  TrustControllerTests) to pass the enum instead of `"inmemory"` /
  `"scylla-postgres"` magic strings.
- AuthLinkControllerTests: delete the fixture-type-switch
  GetPersistenceType() helper and read `fixture.Factory.PersistenceMode`
  directly. Merge ApplyBackendConfiguration into a single
  CreatePrimaryNodeFactory() helper that lifts the four shared
  OCTOCON_SINGLE_SCYLLA_INSTANCE / OCTOCON_DB_RETRY_* calls out of the
  Scylla/Cassandra branches — only the two per-fixture values (Postgres
  connection + CQL port) live inside the switch, as a tuple projection
  (`null` means "InMemory, no external backend").

Verified: dotnet build ./csharp/Interfold.IntegrationTests clean (0 errors);
AuthLinkControllerTests, TrustControllerTests,
ClusterRoleAndOAuthRegistrationTests, InMemorySecretsSeedTests all green
against InMemory, Scylla, and Cassandra fixtures.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Azyyyyyy
Azyyyyyy marked this pull request as ready for review July 20, 2026 06:55
Comment thread csharp/Interfold.Api/Controllers/Base/InterfoldControllerBase.cs
Comment thread csharp/Interfold.Api/Controllers/Base/InterfoldControllerBase.cs Outdated

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

This file seems to have a lot of functions that could be folded together with code changes

Comment thread csharp/Interfold.Api/Controllers/AlterJournalsController.cs Outdated
Comment thread csharp/Interfold.Api/Controllers/AltersController.cs Outdated
Comment thread csharp/Interfold.Infrastructure.Scylla/Repository/ScyllaSharedQueries.cs Outdated
Comment thread csharp/Interfold.Infrastructure.Scylla/Repository/ScyllaSharedQueries.cs Outdated
Comment thread csharp/Interfold.Infrastructure.Scylla/Repository/ScyllaTagRepository.cs Outdated
Comment thread csharp/Interfold.Infrastructure.Scylla/ScyllaUserRegistryRegionContext.cs Outdated
Comment thread csharp/Interfold.Infrastructure.Scylla/ScyllaUserRegistryRegionContext.cs Outdated
Azyyyyyy and others added 7 commits July 21, 2026 18:20
Addresses the low-risk items from the PR #12 review canvas:

- #16 delete csharp/Interfold.Domain/refactor.ps1 (obsolete helper, no callers).
- OctoconDev#23 swap Array.Empty<AlterPublicFieldReadModel>() for [] in
  ScyllaSharedQueries.ResolveAlterFields.
- #20 shrink the six-line security_level rationale on
  ScyllaAlterRepository.CreateAsync to a single line pointing at
  ScyllaAlterRepositoryUdtNullTests.
- #25 same treatment for the seven-line duplicate on
  ScyllaTagRepository.CreateAsync — points at the shared invariant.
- #26 / #27 trim the two INTENTIONAL-fallback comments in
  ScyllaUserRegistryRegionContext.LookupAsync and HandleForLookup to two
  lines each.

No behavioural change. Build clean (0 errors, 102 pre-existing warnings).

Co-authored-by: Cursor <cursoragent@cursor.com>
- #18 / #19 InMemoryFrontingRepository — drop the nullable-and-defaulted
  ctor parameters on `_friendships` / `_alters` and their fields. DI wires
  both (InMemoryServiceCollectionExtensions.AddInMemoryPersistence) so the
  nullability wasn't buying anything and the two guard branches in
  ListActiveAsync / ListActiveGuardedAsync would silently hide a DI mis-
  wiring instead of surfacing it. Collapses the "have `_alters` or fall
  back to a placeholder" branch back to a single expression.

- OctoconDev#24 ScyllaSharedQueries.ResolveAlterFields — swap the FirstOrDefault
  scan for a Dictionary<Guid, string?> keyed by field id so the per-
  definition projection is O(N + M) instead of O(N * M). Same visible
  behaviour on the wire; a system with a handful of alters and a handful
  of settings-field definitions no longer allocates a fresh iterator per
  definition. Also reverts the manual `def.Id.Value` unwrap to `def.Id`
  and lets FieldId's implicit-to-Guid operator do the work — matches
  wrapper-typed comparison intent from the review.

- #15 New AlterCommandFlowExecutionTests — three targeted tests that pin
  UpdateAlterCommandHandler's reject / mutation-failed / happy-path
  branches through the same call-count assertion style as
  PollCommandFlowExecutionTests. The MissingAlter case is the specific
  coverage gap the review flagged; the other two guard against a future
  refactor accidentally catching the accept path in the reject branch.

Build clean (0 errors). New tests: 3 pass. Neighbour suites (Front*, Alter*)
all pass.

Co-authored-by: Cursor <cursoragent@cursor.com>
…isers)

- #7 / #8 / #9 Convert UpdateAlterCommand from a positional record to a
  body-only `{ get; init; }` record with `required` on AlterId and
  UpdatedAt. Everything else is either naturally-null or defaults to
  false, so callers no longer have to spell out 13-14 nulls positionally
  just to change one field.

- Update every call site to the property-initialiser form:
  - AltersController.Update (PATCH) — the "meaningful args" path.
  - AltersController.UploadAvatarMultipart / UploadAvatarByUrl /
    DeleteAvatar — the three review-flagged sites where a 15-arg
    positional call with 12 nulls was the specific complaint.
  - SimplyPluralImportService (two call sites — the initial import
    upsert and the avatar-rehost post-download update).
  - InMemoryAlterRepositoryTests (three sites) and the new
    AlterCommandFlowExecutionTests helper.

Declaration order of the properties is preserved, so JSON serialisation
of the payload — and therefore idempotency-key hashing — is byte-for-
byte identical. Build clean (0 errors). Alter tests all pass (9/9).

Co-authored-by: Cursor <cursoragent@cursor.com>
- #11 Add IAccountRepository.GetPublicSystemAsync returning
  PublicSystemReadModel? directly. Callers of the public wire view
  (currently just PublicSystemsController.Show) no longer have to fetch
  the wider AccountPublicProfileReadModel and hand-project 5 of its 8
  fields at the controller layer — the repo returns exactly the fields
  the wire response carries.

- InMemory adapter mirrors the existing GetPublicProfileAsync existence
  rule (a "present" account is one where any identity-bearing field or
  provider link is set) so the two projections agree — if
  GetPublicProfileAsync returns non-null, GetPublicSystemAsync must too,
  otherwise SystemMustExistAttribute would let a request through that
  Show then 404s.

- Scylla adapter uses a narrower SELECT (no discord/email/apple
  columns) since the public wire projection intentionally drops them.

- PublicSystemsController.Show shrinks from a 13-line project-and-null-
  check to a 5-line qualify-and-return. AccountPublicProfileReadModel
  and GetPublicProfileAsync are retained for other callers that legitimately
  need the identity-link surface (WebSocket init, FCM push,
  SettingsController's avatar helpers).

Build clean (0 errors). Account tests pass (3/3).

Co-authored-by: Cursor <cursoragent@cursor.com>
Collapses six overlapping surfaces on InterfoldControllerBase (and the
matching controller call sites) that the PR review picked apart:

- #10 BuildEnvelope null-safe. Introduces a private TryGetPrincipalId
  that returns nullable, and a private-static AnonymousPrincipalId
  ("nam:auth") sentinel. BuildEnvelope now stamps the sentinel when the
  request is anonymous instead of throwing — the OAuth handlers behind
  AuthController.Callback and AuthLinkController.Callback resolve the
  real system id off the payload, so command.PrincipalId is never read.
  Both callback controllers drop their hand-rolled CommandEnvelope
  constructions and call BuildEnvelope directly.

- OctoconDev#2 Combine the two "no bytes uploaded" avatar helpers. Extract the
  shared read-current / update / cleanup-old-local tail into a private
  RunAvatarMetadataChangeAsync. HandleAvatarUrlUploadAsync becomes URL
  validation + delegation; HandleAvatarDeleteAsync is a one-line
  delegate.

- #3 Collapse the three DispatchCreatedAsync overloads. The sync
  (Func<TResult, TData>) overload had no callers — deleted. The two
  async overloads merge into one with an optional locationSelector.
  Every DispatchCreatedAsync call site is rewrapped to the new shape.

- #5 Delete the replaySelector plumbing. TResult already carries Replay
  via ICommandResult, and every existing selector was literally
  `res => res?.Replay`. Add `where T : ICommandResult` to CommandCreated
  / CommandCreatedAsync and read result.Result!.Replay directly; drop
  the Func<T?, bool?>? replaySelector param from every signature and
  every call site.

- #12 Extract generic DispatchOkAsync<TPayload, TResult, TWire>. Wraps
  the accepted / conflict split around a wire-projection lambda so
  SettingsController.SetupEncryption / RecoverEncryption stop needing a
  private per-controller helper. The removed DispatchEncryptionKeyAsync
  becomes a two-line ToEncryptionKeyResponse projection.

- #4 (general "too many functions") is addressed by the above five: 3
  fewer public/protected methods on the base, and two fewer replay-
  selector parameters everywhere.

Build clean (0 errors). Api.UnitTests: 380/380 pass.

Co-authored-by: Cursor <cursoragent@cursor.com>
…andler (#17)

Finishes the migration flagged by review comment #17: every settings-shaped
handler now inherits IdempotentCommandHandler<TCmd, SettingsCommandResult>
and delegates the mutate → check → publish → success body to the existing
SettingsIdempotentCommandFlow.ExecuteMutationAsync helper. SettingsCommandHelper
had been documented as the "old path for handlers that don't inherit from
IdempotentCommandHandler" — this batch removes the last such handlers, so the
type is deleted rather than left as a discovery hazard.

Handlers converted (11 total):
 - Avatar:   UploadAvatarCommandHandler, DeleteAvatarCommandHandler
 - Identity: UnlinkAppleCommandHandler, UnlinkDiscordCommandHandler, UnlinkEmailCommandHandler
 - Fields:   DeleteFieldCommandHandler, RelocateFieldCommandHandler, UpdateFieldCommandHandler
 - Wipes:    WipeTagsCommandHandler, WipeAltersCommandHandler
 - Delete:   DeleteAccountCommandHandler

Uniform conversion pattern per handler:
 - Base: ICommandHandler<TCmd, SettingsCommandResult>
      → IdempotentCommandHandler<TCmd, SettingsCommandResult>
 - Constructor forwards IIdempotencyStore to `: base(idempotencyStore)`
   and drops the private `_idempotencyStore` field.
 - HandleAsync → ExecuteCoreAsync + `DuplicateEntityRef` override.
 - Body: SettingsCommandHelper.ExecuteAndPublishAsync[/FieldsChangedAsync]
      → SettingsIdempotentCommandFlow.ExecuteMutationAsync
   The field-changed variant folds into the general helper by passing the
   `SettingsFieldsChangedEvent` publisher lambda inline at the call site.
 - UploadAvatar keeps its RejectIfBlank guard on Payload.AvatarUrl (now via
   the base class's protected RejectIfBlank helper, not the static one on
   CommandHandler).
 - DeleteAccount keeps its shared `unfriendedIds` list between the mutation
   and publish lambdas — IdempotentCommandHandler skips ExecuteCoreAsync on
   replay, which is the same guarantee the previous Result.Replay: false
   guard on the old helper gave, so the FriendshipRemovedEvent fan-out
   still only runs on the first-time accept.

SettingsCommandHelper.cs deleted. XmlDoc <see cref> references to it in
SettingsFieldCommandFlow, SettingsIdempotentCommandFlow, and
SettingsEventBusExtensions are re-pointed at the surviving flow helpers so
the docs compile clean. Plain-text mentions in ImportSpCommandHandler,
EntityRefs.SettingsActionFailed, and the InMemoryAccountRepository regression
test's Because() string are rewritten to describe the flow generically.

Build clean (0 errors, warnings unchanged). Api.UnitTests: 380/380 pass.
…merge (#6, #14)

Two review threads folded together because they touch the same axis
(shared shapes across wrapper structs / avatar-carrying read models).

#14 — Fold SecretStringJsonConverter<T> into StringBackedJsonConverter<T>.
The two abstract JSON converters had byte-for-byte identical bodies (Read
via reader.GetString() ?? string.Empty, Write via writer.WriteStringValue).
The only "secret" behaviour is on each struct's own ToString() override
via SecretRedaction.Redact — the converter itself always emits the raw
string at the wire boundary, in both families. Delete SecretStringJsonConverter<T>
and re-point the six concrete converters (LinkToken / PushToken / ImportToken /
RecoveryCode / Jti / SocketToken) at StringBackedJsonConverter<T>. SecretRedaction
stays for the six struct-level ToString() overrides that still redact.
StringBackedJsonConverter<T>'s xml-doc is expanded to list all 17 wrapper
structs (11 public + 6 secret) it now covers and to note that the
"secret" spelling lives on struct ToString(), not the converter. The
Guid-backed sibling (GuidIdJsonConverter<T>) stays separate — its wire
body is a Guid, not a string.

#6 — Introduce IAvatarBearing so QualifyAvatar callsites stop threading
the (AvatarUrl?, AvatarSource?) pair by hand. New interface in
Interfold.Contracts.Models with AvatarUrl? / AvatarSource? getters.
Implemented by six read-shape carriers: BareAlter (and AlterReadModel by
inheritance), FriendProfileReadModel, FriendFrontingAlterReadModel,
PublicSystemReadModel, AccountPublicProfileReadModel, SocketSelfReadModel.
Positional records satisfy the interface's { get; } declarations via
their generated { get; init; } properties — no per-record body needed.

AvatarUrlQualifier gains two new overloads:
  QualifyAvatar(IAvatarBearing?, string scheme, HostString host)
  QualifyAvatar(IAvatarBearing?, string? origin)
Both accept a null bearing and pass it through as null so the
`profile?...` pattern at socket boundaries stays a one-liner. The three
existing (AvatarUrl?, AvatarSource?, ...) overloads stay for the couple
of callers that hold the pair without a wrapping bearing (e.g.
WebSocketInitialization's SocketSelfReadModel construction, where the
"bearing" is being built rather than consumed).

Callsites simplified: AltersController.Show,
PublicSystemsController.Show / ListAlters / ShowAlter / Batch,
InterfoldControllerBase.QualifyAvatar (base helper),
AlterSocketEventHandlers.HandleUpsertAsync,
FriendshipSocketEventHandlers, WebSocketInitialization's own
per-alter qualification and the BuildSelfReadModel `profile?` call.
Every `QualifyAvatar(x.AvatarUrl, x.AvatarSource, ...)` becomes
`QualifyAvatar(x, ...)`.

Build clean (0 errors). Api.UnitTests: 380/380 pass.
Comment thread csharp/Interfold.Api/Controllers/AuthLinkController.cs Outdated
@github-actions

Copy link
Copy Markdown

Summary

Summary
Generated on: 07/21/2026 - 18:49:22
Parser: MultiReport (4x Cobertura)
Assemblies: 11
Classes: 730
Files: 461
Line coverage: 68.7% (21538 of 31341)
Covered lines: 21538
Uncovered lines: 9803
Coverable lines: 31341
Total lines: 54180
Branch coverage: 58% (5310 of 9148)
Covered branches: 5310
Total branches: 9148
Method coverage: Feature is only available for sponsors
Tag: 120_29857013383

Coverage

interfold-bootstrap - 64.4%
Name Line Branch
interfold-bootstrap 64.4% 62.8%
Interfold.Bootstrapper.Cli.BootstrapCommandExtensions 66.6% 40%
Interfold.Bootstrapper.Cli.BootstrapOptions 100%
Interfold.Bootstrapper.Cli.PhaseLogger 100% 50%
Interfold.Bootstrapper.Cli.RootCli 81.7% 55.2%
Interfold.Bootstrapper.Configuration.ApiRuntimeSection 100%
Interfold.Bootstrapper.Configuration.BackupSection 100%
Interfold.Bootstrapper.Configuration.BootstrapConfig 100%
Interfold.Bootstrapper.Configuration.BootstrapJsonContext 82.6% 88.8%
Interfold.Bootstrapper.Configuration.ClusterSection 100%
Interfold.Bootstrapper.Configuration.DeploymentSection 100%
Interfold.Bootstrapper.Configuration.FirebaseFolderScanner 100% 100%
Interfold.Bootstrapper.Configuration.FirebaseFolderScanResult 100%
Interfold.Bootstrapper.Configuration.FirebaseSection 100%
Interfold.Bootstrapper.Configuration.GeneratedSecrets 100%
Interfold.Bootstrapper.Configuration.HostEntry 100%
Interfold.Bootstrapper.Configuration.HostnameDetector 100% 100%
Interfold.Bootstrapper.Configuration.HostParser 100% 97%
Interfold.Bootstrapper.Configuration.LocalAddressDetector 98.7% 100%
Interfold.Bootstrapper.Configuration.MdnsAvailability 22% 7.1%
Interfold.Bootstrapper.Configuration.OAuthSection 100%
Interfold.Bootstrapper.Configuration.ObservabilitySection 100%
Interfold.Bootstrapper.Configuration.PersistenceTuningSection 100%
Interfold.Bootstrapper.Configuration.PortsSection 100%
Interfold.Bootstrapper.Configuration.StorageSection 100%
Interfold.Bootstrapper.Configuration.UpdateSection 100%
Interfold.Bootstrapper.Phases.BackupDatabaseComponentExtensions 15.7% 0%
Interfold.Bootstrapper.Phases.BackupPhase 1.7% 0%
Interfold.Bootstrapper.Phases.BackupRetention 0% 0%
Interfold.Bootstrapper.Phases.BackupStoragePaths 100% 100%
Interfold.Bootstrapper.Phases.BootstrapArtifactPaths 20% 16.6%
Interfold.Bootstrapper.Phases.BootstrapPhaseExtensions 42.8% 10%
Interfold.Bootstrapper.Phases.CassandraImagePhase 8.6% 0%
Interfold.Bootstrapper.Phases.CertificatePhase 78.3% 72.9%
Interfold.Bootstrapper.Phases.ComposeExecPostgresExecutor 0% 0%
Interfold.Bootstrapper.Phases.ComposeExecScyllaExecutor 0% 0%
Interfold.Bootstrapper.Phases.ConfigPhase 90% 88%
Interfold.Bootstrapper.Phases.DatabaseInitPhase 39.3% 0%
Interfold.Bootstrapper.Phases.FirebasePhase 93.7% 100%
Interfold.Bootstrapper.Phases.FirebaseSeedInputs 100%
Interfold.Bootstrapper.Phases.LaunchPhase 0% 0%
Interfold.Bootstrapper.Phases.Orchestrator 17.4% 12.1%
Interfold.Bootstrapper.Phases.PhaseArtifactLoader 0% 0%
Interfold.Bootstrapper.Phases.PhaseLoggerAdapter 0%
Interfold.Bootstrapper.Phases.PrerequisitesPhase 0% 0%
Interfold.Bootstrapper.Phases.PublishPhase 47.2% 64.4%
Interfold.Bootstrapper.Phases.PublishPhase.EnvReplacements 100%
Interfold.Bootstrapper.Phases.RestorePhase 8.5% 0%
Interfold.Bootstrapper.Phases.SecretsPhase 90.9% 85.7%
Interfold.Bootstrapper.Phases.SystemdInstallPhase 35.5% 33.3%
Interfold.Bootstrapper.Phases.SystemdInstallPhase.SystemdRenderInput 100%
Interfold.Bootstrapper.Phases.UpdateImagesPhase 28.7% 42.8%
Interfold.Bootstrapper.Program 100%
Interfold.Bootstrapper.Util.ApiReadinessProbe 0% 0%
Interfold.Bootstrapper.Util.ComposeLogDumper 0% 0%
Interfold.Bootstrapper.Util.DatabaseArchiveStreamer 0% 0%
Interfold.Bootstrapper.Util.DistroInfo 91.8% 65.6%
Interfold.Bootstrapper.Util.DockerCompose 32.6% 16.1%
Interfold.Bootstrapper.Util.DockerComposeExec 0% 0%
Interfold.Bootstrapper.Util.EmbeddedSupportFiles 100% 100%
Interfold.Bootstrapper.Util.PhaseRunner 0% 0%
Interfold.Bootstrapper.Util.PostgresReadinessProbe 12.2% 0%
Interfold.Bootstrapper.Util.ProcessRunner 0% 0%
Interfold.Bootstrapper.Util.ProcessRunResult 0%
Interfold.Bootstrapper.Util.ProcessStreamRunner 0% 0%
Interfold.Bootstrapper.Util.ScyllaReadinessProbe 0% 0%
Interfold.Bootstrapper.Util.UnixFilePermissions 93.9% 100%
Interfold.Bootstrapper.Util.UnixFilePermissions.NativeMethods 100%
Interfold.Api - 65.5%
Name Line Branch
Interfold.Api 65.5% 55.4%
Interfold.Api.Auth.JwtEs256Validator 66.8% 63.4%
Interfold.Api.Auth.OAuthChallengeServiceCollectionExtensions 100% 100%
Interfold.Api.Auth.PemUtil 90.9% 50%
Interfold.Api.Auth.RedirectChallengeAuthenticationHandler 85.7% 75%
Interfold.Api.Auth.ValidationResult 100%
Interfold.Api.Controllers.AlterJournalsController 91.1%
Interfold.Api.Controllers.AltersController 96.4% 60%
Interfold.Api.Controllers.AuthController 70.2% 45%
Interfold.Api.Controllers.AuthLinkController 56.2% 46.1%
Interfold.Api.Controllers.Base.InterfoldControllerBase 64.7% 59%
Interfold.Api.Controllers.Base.InterfoldControllerBase<T, TData> 64.7% 59%
Interfold.Api.Controllers.Base.InterfoldControllerBase<TPayload, TResult, T
Data>
64.7% 59%
Interfold.Api.Controllers.Base.InterfoldControllerBase<TPayload, TResult, T
Wire>
64.7% 59%
Interfold.Api.Controllers.Base.InterfoldControllerBase<TPayload, TResult> 64.7% 59%
Interfold.Api.Controllers.Base.OAuthControllerBase 41.6% 25%
Interfold.Api.Controllers.FriendRequestsController 100% 100%
Interfold.Api.Controllers.FriendsController 100% 100%
Interfold.Api.Controllers.FrontingController 72.9% 62.5%
Interfold.Api.Controllers.JournalsController 83.9%
Interfold.Api.Controllers.NodeRoleController 100%
Interfold.Api.Controllers.PollsController 85% 50%
Interfold.Api.Controllers.PublicSystemsController 65.7% 41.6%
Interfold.Api.Controllers.SettingsController 56.5% 20.4%
Interfold.Api.Controllers.TagsController 90.7% 50%
Interfold.Api.Controllers.TrustController 90.9% 84.6%
Interfold.Api.Filters.SystemMustExistAttribute 39.3% 31.2%
Interfold.Api.Helpers.AvatarServingPolicy 95% 93.3%
Interfold.Api.Helpers.AvatarUrlQualifier 59.4% 38.2%
Interfold.Api.Helpers.AvatarUrlValidator 53.5% 71.4%
Interfold.Api.Helpers.Base64Extensions 100% 100%
Interfold.Api.Helpers.FirebaseConfigResolver 95.2% 75%
Interfold.Api.Helpers.HealthCheckExtensions 100%
Interfold.Api.Helpers.InterfoldMetrics 100%
Interfold.Api.Helpers.LoopbackHttpClient 100%
Interfold.Api.Helpers.RecoveryCodeResolver 0% 0%
Interfold.Api.Middleware.InterfoldPrincipalMiddleware 100% 88.8%
Interfold.Api.Middleware.RequestCorrelationMiddleware 94.2% 50%
Interfold.Api.ModelBinding.UnixSecondsBindingAttribute 100%
Interfold.Api.ModelBinding.UnixSecondsModelBinder 91.5% 81.2%
Interfold.Api.ModelBinding.UnixSecondsModelBinderProvider 100% 100%
Interfold.Api.Models.EncryptionKeyResponse 0%
Interfold.Api.Models.ErrorMessageResponse 100%
Interfold.Api.Models.ErrorResponse 100%
Interfold.Api.Models.FieldCreatedResponse 100%
Interfold.Api.Models.FirebaseAndroidConfigResponse 100%
Interfold.Api.Models.FirebaseIosConfigResponse 100%
Interfold.Api.Models.FirebaseWebConfigResponse 100%
Interfold.Api.Models.ImportDispatchResponse 100%
Interfold.Api.Models.LinkTokenUnavailableResponse 0%
Interfold.Api.Models.NodeRoleResponse 100%
Interfold.Api.Models.Response 100%
Interfold.Api.Models.Response 87.8% 100%
Interfold.Api.Models.SuccessResponse 100%
Interfold.Api.Models.UnixSeconds 78.5% 75%
Interfold.Api.Models.UnsupportedOAuthProviderResponse 0%
Interfold.Api.Services.AppleOAuthService 8.6% 0%
Interfold.Api.Services.DiscordOAuthService 10.8% 0%
Interfold.Api.Services.ExceptionHandler 0% 0%
Interfold.Api.Services.GoogleOAuthService 12.1% 0%
Interfold.Api.Services.Http.HttpLoggingHandler 0% 0%
Interfold.Api.Services.Http.HttpLoggingJsonContext 0% 0%
Interfold.Api.Services.ImportJobs.ImportJobBackgroundService 72.7% 54.1%
Interfold.Api.Services.ImportJobs.PkImportJobRunner 100%
Interfold.Api.Services.ImportJobs.SpImportJobRunner 100%
Interfold.Api.Services.LocalAvatarStorage 79.3% 50%
Interfold.Api.Services.Secrets.AuthenticationSecretsPostConfigure 100% 100%
Interfold.Api.Services.Secrets.FcmSecretsPostConfigure 100% 100%
Interfold.Api.Services.Secrets.FirebaseClientSecretsPostConfigure 92.8% 87.5%
Interfold.Api.Services.Secrets.SecretsPreBuildLoader 79.6% 67.8%
Interfold.Api.Services.Secrets.SecretsSnapshot 100% 100%
Interfold.Api.Services.SimplyPlural.SpApiPaths 88.8%
Interfold.Api.Services.SimplyPlural.SpCdnHosts 85.7%
Interfold.Api.Services.SimplyPlural.SpEntity 100%
Interfold.Api.Services.SimplyPlural.SpGroupContent 100%
Interfold.Api.Services.SimplyPlural.SpJsonContext 76% 80.4%
Interfold.Api.Services.SimplyPlural.SpMemberContent 100%
Interfold.Api.Services.SimplyPlural.SpObjectId 100% 90.9%
Interfold.Api.Services.SimplyPluralImportService 67% 55.4%
Interfold.Api.Services.SimplyPluralImportService.AvatarDownload 0%
Interfold.Api.Services.SimplyPluralImportService 67% 55.4%
Interfold.Api.Services.StartupProbeConfigurationProxy 70.3% 83.3%
Interfold.Api.Services.ValidationErrorCodeRegistry 81.8% 75%
Interfold.Api.SimplyPlural.SimplyPluralImportExtensions 100%
Interfold.Api.Socket.Handlers.AlterSocketEventHandlers 69.2%
Interfold.Api.Socket.Handlers.FriendshipSocketEventHandlers 88.1% 57.6%
Interfold.Api.Socket.Handlers.FriendshipSocketEventHandlers 88.1% 57.6%
Interfold.Api.Socket.Handlers.FrontingSocketEventHandlers 23.8% 50%
Interfold.Api.Socket.Handlers.ImportSocketEventHandlers 100%
Interfold.Api.Socket.Handlers.JournalSocketEventHandlers 0% 0%
Interfold.Api.Socket.Handlers.PollSocketEventHandlers 0% 0%
Interfold.Api.Socket.Handlers.SettingsSocketEventHandlers 21.7% 20%
Interfold.Api.Socket.Handlers.TagSocketEventHandlers 55.5% 100%
Interfold.Api.Socket.PhoenixInboundFrame 83.1% 60.8%
Interfold.Api.Socket.SocketEventPumpRunner 42.6% 0%
Interfold.Api.Socket.SocketEventPumpRunner 42.6% 0%
Interfold.Api.Socket.SocketJoinRateLimiter 83.3% 87.5%
Interfold.Api.Socket.SocketPushContext 88.8% 57.1%
Interfold.Api.Socket.SocketPushContext<TEntity, TPayload> 88.8% 57.1%
Interfold.Api.Socket.SystemTopic 80.9% 58.3%
Interfold.Api.Socket.WebSocketEvents 88.4% 50%
Interfold.Api.Socket.WebSocketEvents 88.4% 50%
Interfold.Api.Socket.WebSocketHandler 72.2% 65.7%
Interfold.Api.Socket.WebSocketHandler 72.2% 65.7%
Interfold.Api.Socket.WebSocketInitialization 79.2% 59.5%
Interfold.Api.Socket.WebSocketInitialization<TItem, TPayload> 79.2% 59.5%
Interfold.Api.Swagger.HealthCheckDocumentFilter 0%
Interfold.Api.Swagger.MultipleContentTypeOperationFilter 0% 0%
Program 83.7% 66.4%
Interfold.AppHost - 44.9%
Name Line Branch
Interfold.AppHost 44.9% 48.6%
Interfold.AppHostGraph.ComposeHealthcheck 0%
Interfold.AppHostGraph.DockerExecCqlProbe 66.9% 37.5%
Interfold.AppHostGraph.HostPortTcpProbe 0%
Interfold.AppHostGraph.ImageRef 0% 0%
Interfold.AppHostGraph.InterfoldAppHost 43.3% 54.7%
Interfold.AppHostGraph.PersistentResourceExtensions 0%
Program 100%
Interfold.Contracts - 78.8%
Name Line Branch
Interfold.Contracts 78.8% 60.5%
Interfold.Contracts.AccountCommandResult 100%
Interfold.Contracts.AccountLinkFlag 100%
Interfold.Contracts.AccountLinkFlagJsonConverter 72.7% 50%
Interfold.Contracts.AlterCommandResult 100%
Interfold.Contracts.AlterDeletedSocketPayload 0%
Interfold.Contracts.AlterIdSocketPayload 0%
Interfold.Contracts.AlterJournalCommandResult 50%
Interfold.Contracts.AlterJournalSocketPayload 0%
Interfold.Contracts.AlterSocketPayload 100%
Interfold.Contracts.AppleAccountLinkedPayload 0%
Interfold.Contracts.BodyJson 23.5% 12.5%
Interfold.Contracts.BodyJsonConverterFactory 100%
Interfold.Contracts.Configuration.AppHostParameterKeys 100% 50%
Interfold.Contracts.Configuration.AuthenticationConfiguration 100%
Interfold.Contracts.Configuration.BoolWire 100% 75%
Interfold.Contracts.Configuration.ClusterConfiguration 100%
Interfold.Contracts.Configuration.ComposeServices 100% 100%
Interfold.Contracts.Configuration.ComposeVolumes 0%
Interfold.Contracts.Configuration.CorsOptions 30.7% 25%
Interfold.Contracts.Configuration.FirebaseAndroidClientConfig 100%
Interfold.Contracts.Configuration.FirebaseIosClientConfig 100%
Interfold.Contracts.Configuration.FirebaseWebClientConfig 100%
Interfold.Contracts.Configuration.PersistenceConfiguration 91.1% 50%
Interfold.Contracts.Configuration.ScyllaTopologyExtensions 88.8% 83.3%
Interfold.Contracts.Configuration.TestingConfiguration 0%
Interfold.Contracts.Configuration.Validation.AbsoluteHttpUriAttribute 100% 62.5%
Interfold.Contracts.Configuration.Validation.AbsolutePathAttribute 100% 55%
Interfold.Contracts.DiscordAccountLinkedPayload 0%
Interfold.Contracts.EncryptionCommandResult 0%
Interfold.Contracts.EntryDeletedSocketPayload 0%
Interfold.Contracts.Enums.EnumCode 70.9% 66.6%
Interfold.Contracts.Enums.EnumCodeExtensions 42.8%
Interfold.Contracts.Enums.EnumWire 100% 80%
Interfold.Contracts.Enums.EnumWireExtensions 59% 83.3%
Interfold.Contracts.Enums.TolerantWireEnumJsonConverter 71.4% 75%
Interfold.Contracts.ErrorCode 75% 50%
Interfold.Contracts.ErrorCodeJsonConverter 100%
Interfold.Contracts.ErrorCodes 100%
Interfold.Contracts.ErrorCodes.SocketReasons 100%
Interfold.Contracts.Events.AlterCreatedEvent 100%
Interfold.Contracts.Events.AlterDeletedEvent 100%
Interfold.Contracts.Events.AlterJournalEntryCreatedEvent 100%
Interfold.Contracts.Events.AlterJournalEntryDeletedEvent 100%
Interfold.Contracts.Events.AlterJournalEntryUpdatedEvent 100%
Interfold.Contracts.Events.AlterUpdatedEvent 100%
Interfold.Contracts.Events.FriendRequestReceivedEvent 100%
Interfold.Contracts.Events.FriendRequestRemovedFromEvent 100%
Interfold.Contracts.Events.FriendRequestRemovedToEvent 100%
Interfold.Contracts.Events.FriendRequestSentEvent 100%
Interfold.Contracts.Events.FriendshipAddedEvent 100%
Interfold.Contracts.Events.FriendshipRemovedEvent 100%
Interfold.Contracts.Events.FriendshipTrustedEvent 100%
Interfold.Contracts.Events.FriendshipUntrustedEvent 100%
Interfold.Contracts.Events.FrontCommentUpdatedEvent 0%
Interfold.Contracts.Events.FrontDeletedEvent 100%
Interfold.Contracts.Events.FrontingBulkUpdatedEvent 0%
Interfold.Contracts.Events.FrontingEndedEvent 100%
Interfold.Contracts.Events.FrontingPrimaryChangedEvent 0%
Interfold.Contracts.Events.FrontingSetEvent 100%
Interfold.Contracts.Events.FrontingStartedEvent 100%
Interfold.Contracts.Events.FrontingStateChangedEvent 100%
Interfold.Contracts.Events.GlobalJournalEntryCreatedEvent 100%
Interfold.Contracts.Events.GlobalJournalEntryDeletedEvent 100%
Interfold.Contracts.Events.GlobalJournalEntryUpdatedEvent 100%
Interfold.Contracts.Events.PluralKitImportCompletedEvent 100%
Interfold.Contracts.Events.PluralKitImportFailedEvent 100%
Interfold.Contracts.Events.PollCreatedEvent 100%
Interfold.Contracts.Events.PollDeletedEvent 100%
Interfold.Contracts.Events.PollUpdatedEvent 100%
Interfold.Contracts.Events.SettingsAccountDeletedSignalEvent 0%
Interfold.Contracts.Events.SettingsAltersWipedSignalEvent 0%
Interfold.Contracts.Events.SettingsAppleAccountLinkedEvent 0%
Interfold.Contracts.Events.SettingsAppleAccountUnlinkedSignalEvent 0%
Interfold.Contracts.Events.SettingsDiscordAccountLinkedEvent 100%
Interfold.Contracts.Events.SettingsDiscordAccountUnlinkedSignalEvent 0%
Interfold.Contracts.Events.SettingsEncryptedDataWipedSignalEvent 0%
Interfold.Contracts.Events.SettingsFieldsChangedEvent 100%
Interfold.Contracts.Events.SettingsGoogleAccountLinkedEvent 0%
Interfold.Contracts.Events.SettingsGoogleAccountUnlinkedSignalEvent 100%
Interfold.Contracts.Events.SettingsProfileUpdatedEvent 100%
Interfold.Contracts.Events.SettingsTagsWipedSignalEvent 100%
Interfold.Contracts.Events.SimplyPluralImportCompletedEvent 100%
Interfold.Contracts.Events.SimplyPluralImportFailedEvent 100%
Interfold.Contracts.Events.TagCreatedEvent 100%
Interfold.Contracts.Events.TagDeletedEvent 100%
Interfold.Contracts.Events.TagUpdatedEvent 100%
Interfold.Contracts.FriendIdSocketPayload 100%
Interfold.Contracts.FriendRequestSocketPayload 100%
Interfold.Contracts.FriendshipCommandResult 100%
Interfold.Contracts.FrontCommandResult 100%
Interfold.Contracts.FrontIdSocketPayload 0%
Interfold.Contracts.FrontSocketPayload 100%
Interfold.Contracts.FrontsSocketPayload 0%
Interfold.Contracts.GlobalJournalCommandResult 100%
Interfold.Contracts.GlobalJournalSocketPayload 0%
Interfold.Contracts.GoogleAccountLinkedPayload 0%
Interfold.Contracts.Ids.AlterId 85.7% 66.6%
Interfold.Contracts.Ids.AlterIdJsonConverter 100%
Interfold.Contracts.Ids.AppleId 60% 50%
Interfold.Contracts.Ids.AppleIdJsonConverter 0%
Interfold.Contracts.Ids.AvatarUrl 85.7% 75%
Interfold.Contracts.Ids.AvatarUrlJsonConverter 100%
Interfold.Contracts.Ids.DiscordId 60% 50%
Interfold.Contracts.Ids.DiscordIdJsonConverter 0%
Interfold.Contracts.Ids.Email 60% 50%
Interfold.Contracts.Ids.EmailJsonConverter 0%
Interfold.Contracts.Ids.EncryptionKeyMaterial 60% 50%
Interfold.Contracts.Ids.EncryptionKeyMaterialJsonConverter 0%
Interfold.Contracts.Ids.EncryptionSalt 71.4% 50%
Interfold.Contracts.Ids.EntityRef 50% 50%
Interfold.Contracts.Ids.EntityRefJsonConverter 0%
Interfold.Contracts.Ids.EntityVersion 0%
Interfold.Contracts.Ids.EntityVersionJsonConverter 0%
Interfold.Contracts.Ids.EntryId 50% 50%
Interfold.Contracts.Ids.EntryIdJsonConverter 66.6%
Interfold.Contracts.Ids.FieldId 50% 50%
Interfold.Contracts.Ids.FieldIdJsonConverter 66.6%
Interfold.Contracts.Ids.FriendLookup 96.8% 100%
Interfold.Contracts.Ids.FriendLookupJsonConverter 14.2% 0%
Interfold.Contracts.Ids.FrontId 61.5% 50%
Interfold.Contracts.Ids.FrontIdJsonConverter 66.6%
Interfold.Contracts.Ids.GuidIdJsonConverter 100% 50%
Interfold.Contracts.Ids.HexColor 94.4% 100%
Interfold.Contracts.Ids.HexColorJsonConverter 100% 75%
Interfold.Contracts.Ids.IdempotencyKey 20% 25%
Interfold.Contracts.Ids.IdempotencyKeyJsonConverter 0%
Interfold.Contracts.Ids.ImportOperationId 50%
Interfold.Contracts.Ids.ImportOperationIdJsonConverter 100%
Interfold.Contracts.Ids.ImportToken 60% 50%
Interfold.Contracts.Ids.ImportTokenJsonConverter 100%
Interfold.Contracts.Ids.Jti 85.7% 75%
Interfold.Contracts.Ids.JtiJsonConverter 0%
Interfold.Contracts.Ids.KeyChecksum 16.6% 25%
Interfold.Contracts.Ids.LinkToken 83.3% 75%
Interfold.Contracts.Ids.LinkTokenJsonConverter 100%
Interfold.Contracts.Ids.OperationId 20% 25%
Interfold.Contracts.Ids.OperationIdJsonConverter 0%
Interfold.Contracts.Ids.PollId 50% 50%
Interfold.Contracts.Ids.PollIdJsonConverter 66.6%
Interfold.Contracts.Ids.ProviderIdentity 93.3% 83.3%
Interfold.Contracts.Ids.PushToken 60% 50%
Interfold.Contracts.Ids.PushTokenJsonConverter 0%
Interfold.Contracts.Ids.RecoveryCode 60% 50%
Interfold.Contracts.Ids.RecoveryCodeJsonConverter 0%
Interfold.Contracts.Ids.ScopedSystemId 93.4% 92.8%
Interfold.Contracts.Ids.ScopedSystemIdJsonConverter 100% 50%
Interfold.Contracts.Ids.SecretRedaction 100% 100%
Interfold.Contracts.Ids.SocketToken 80% 50%
Interfold.Contracts.Ids.SocketTokenJsonConverter 100%
Interfold.Contracts.Ids.StringBackedJsonConverter 100% 50%
Interfold.Contracts.Ids.SystemId 66.6% 50%
Interfold.Contracts.Ids.SystemIdJsonConverter 100%
Interfold.Contracts.Ids.TagId 58.3% 50%
Interfold.Contracts.Ids.TagIdJsonConverter 66.6%
Interfold.Contracts.Ids.Username 66.6% 50%
Interfold.Contracts.Ids.UsernameJsonConverter 100% 50%
Interfold.Contracts.Ids.UuidString 100% 100%
Interfold.Contracts.ImportCompletedSocketPayload 100%
Interfold.Contracts.ImportDispatchCommandResult 87.5%
Interfold.Contracts.InterfoldException 0%
Interfold.Contracts.Models.AlterPublicFieldReadModel 100%
Interfold.Contracts.Models.AlterReadModel 100%
Interfold.Contracts.Models.BareAlter 100%
Interfold.Contracts.Models.ChoicePollData 100%
Interfold.Contracts.Models.CommandExecutionResult 100%
Interfold.Contracts.Models.Commands.AcceptFriendRequestCommand 100%
Interfold.Contracts.Models.Commands.AddPushTokenCommand 0%
Interfold.Contracts.Models.Commands.AlterFieldCommand 100%
Interfold.Contracts.Models.Commands.AttachAlterToGlobalJournalCommand 100%
Interfold.Contracts.Models.Commands.AttachAlterToTagCommand 100%
Interfold.Contracts.Models.Commands.AuthenticateOAuthCommand 100%
Interfold.Contracts.Models.Commands.BulkUpdateFrontCommand 0%
Interfold.Contracts.Models.Commands.CancelFriendRequestCommand 100%
Interfold.Contracts.Models.Commands.CreateAlterCommand 100%
Interfold.Contracts.Models.Commands.CreateAlterJournalEntryCommand 100%
Interfold.Contracts.Models.Commands.CreateFieldCommand 100%
Interfold.Contracts.Models.Commands.CreateGlobalJournalEntryCommand 100%
Interfold.Contracts.Models.Commands.CreateLinkTokenCommand 100%
Interfold.Contracts.Models.Commands.CreatePollCommand 100%
Interfold.Contracts.Models.Commands.CreateTagCommand 100%
Interfold.Contracts.Models.Commands.DeleteAccountCommand 0%
Interfold.Contracts.Models.Commands.DeleteAlterCommand 100%
Interfold.Contracts.Models.Commands.DeleteAlterJournalEntryCommand 100%
Interfold.Contracts.Models.Commands.DeleteAvatarCommand 0%
Interfold.Contracts.Models.Commands.DeleteFieldCommand 0%
Interfold.Contracts.Models.Commands.DeleteFrontByIdCommand 100%
Interfold.Contracts.Models.Commands.DeleteGlobalJournalEntryCommand 100%
Interfold.Contracts.Models.Commands.DeletePollCommand 100%
Interfold.Contracts.Models.Commands.DeleteTagCommand 100%
Interfold.Contracts.Models.Commands.DetachAlterFromGlobalJournalCommand 0%
Interfold.Contracts.Models.Commands.DetachAlterFromTagCommand 0%
Interfold.Contracts.Models.Commands.EndFrontCommand 100%
Interfold.Contracts.Models.Commands.FrontStartItem 0%
Interfold.Contracts.Models.Commands.ImportPkCommand 100%
Interfold.Contracts.Models.Commands.ImportSpCommand 100%
Interfold.Contracts.Models.Commands.LinkOAuthIdentityCommand 100%
Interfold.Contracts.Models.Commands.RecordAuthTokenCommand 100%
Interfold.Contracts.Models.Commands.RecoverEncryptionCommand 0%
Interfold.Contracts.Models.Commands.RejectFriendRequestCommand 100%
Interfold.Contracts.Models.Commands.RelocateFieldCommand 0%
Interfold.Contracts.Models.Commands.RemoveFriendshipCommand 100%
Interfold.Contracts.Models.Commands.RemoveParentTagCommand 100%
Interfold.Contracts.Models.Commands.RemovePushTokenCommand 0%
Interfold.Contracts.Models.Commands.ResetEncryptionCommand 0%
Interfold.Contracts.Models.Commands.RevokeAuthTokenCommand 0%
Interfold.Contracts.Models.Commands.SendFriendRequestCommand 100%
Interfold.Contracts.Models.Commands.SetAlterJournalLockedCommand 0%
Interfold.Contracts.Models.Commands.SetAlterJournalPinnedCommand 0%
Interfold.Contracts.Models.Commands.SetFriendTrustCommand 100%
Interfold.Contracts.Models.Commands.SetFrontCommand 100%
Interfold.Contracts.Models.Commands.SetGlobalJournalLockedCommand 100%
Interfold.Contracts.Models.Commands.SetGlobalJournalPinnedCommand 100%
Interfold.Contracts.Models.Commands.SetParentTagCommand 100%
Interfold.Contracts.Models.Commands.SetPrimaryFrontCommand 0%
Interfold.Contracts.Models.Commands.SetupEncryptionCommand 0%
Interfold.Contracts.Models.Commands.StartFrontCommand 100%
Interfold.Contracts.Models.Commands.UnlinkAppleCommand 0%
Interfold.Contracts.Models.Commands.UnlinkDiscordCommand 0%
Interfold.Contracts.Models.Commands.UnlinkEmailCommand 100%
Interfold.Contracts.Models.Commands.UpdateAlterJournalEntryCommand 100%
Interfold.Contracts.Models.Commands.UpdateDescriptionCommand 100%
Interfold.Contracts.Models.Commands.UpdateFieldCommand 0%
Interfold.Contracts.Models.Commands.UpdateFrontCommentCommand 0%
Interfold.Contracts.Models.Commands.UpdateGlobalJournalEntryCommand 100%
Interfold.Contracts.Models.Commands.UpdatePollCommand 100%
Interfold.Contracts.Models.Commands.UpdateTagCommand 100%
Interfold.Contracts.Models.Commands.UpdateUsernameCommand 100%
Interfold.Contracts.Models.Commands.UploadAvatarCommand 100%
Interfold.Contracts.Models.Commands.WipeAltersCommand 0%
Interfold.Contracts.Models.Commands.WipeTagsCommand 100%
Interfold.Contracts.Models.EncryptionState 100%
Interfold.Contracts.Models.IdempotencyMatch 100%
Interfold.Contracts.Models.ImportOperations.ImportOperationSnapshot 100%
Interfold.Contracts.Models.PollChoiceId 75% 50%
Interfold.Contracts.Models.PollChoiceIdJsonConverter 50%
Interfold.Contracts.Models.PollDataChoice 100%
Interfold.Contracts.Models.PollDataJson 14.2% 10.7%
Interfold.Contracts.Models.PollDataResponse 100%
Interfold.Contracts.Models.Read.AccountPublicProfileReadModel 100%
Interfold.Contracts.Models.Read.AlterJournalReadModel 100%
Interfold.Contracts.Models.Read.AlterJournalRef 100%
Interfold.Contracts.Models.Read.AvatarUploadPayload 100%
Interfold.Contracts.Models.Read.AvatarUrlUploadRequest 100%
Interfold.Contracts.Models.Read.CreateAlterJournalRequest 100%
Interfold.Contracts.Models.Read.CreateAlterRequest 100%
Interfold.Contracts.Models.Read.CreateGlobalJournalRequest 100%
Interfold.Contracts.Models.Read.CreatePollRequest 100%
Interfold.Contracts.Models.Read.CreateTagRequest 100%
Interfold.Contracts.Models.Read.DeleteGlobalJournalRequest 0%
Interfold.Contracts.Models.Read.FriendFrontingAlterReadModel 0%
Interfold.Contracts.Models.Read.FriendFrontingFrontReadModel 0%
Interfold.Contracts.Models.Read.FriendFrontingReadModel 0%
Interfold.Contracts.Models.Read.FriendProfileReadModel 100%
Interfold.Contracts.Models.Read.FriendRequestIndexReadModel 100%
Interfold.Contracts.Models.Read.FriendRequestMutationOutcomeExtensions 77.7% 50%
Interfold.Contracts.Models.Read.FriendRequestReadModel 100%
Interfold.Contracts.Models.Read.FriendshipModel 100%
Interfold.Contracts.Models.Read.FriendshipReadModel 100%
Interfold.Contracts.Models.Read.FriendshipRequestModel 100%
Interfold.Contracts.Models.Read.FrontActiveReadModel 100%
Interfold.Contracts.Models.Read.FrontBulkUpdateRequest 0%
Interfold.Contracts.Models.Read.FrontCommentRequest 0%
Interfold.Contracts.Models.Read.FrontEndRequest 100%
Interfold.Contracts.Models.Read.FrontHistoryReadModel 100%
Interfold.Contracts.Models.Read.FrontPrimaryRequest 100%
Interfold.Contracts.Models.Read.FrontSetRequest 100%
Interfold.Contracts.Models.Read.FrontStartedResponse 100%
Interfold.Contracts.Models.Read.FrontStartEntry 0%
Interfold.Contracts.Models.Read.FrontStartRequest 100%
Interfold.Contracts.Models.Read.JournalActionRequest 0%
Interfold.Contracts.Models.Read.JournalAlterRequest 100%
Interfold.Contracts.Models.Read.JournalReadModel 100%
Interfold.Contracts.Models.Read.LinkTokenReadModel 100%
Interfold.Contracts.Models.Read.PollReadModel 100%
Interfold.Contracts.Models.Read.PublicSystemBatchReadModel 0%
Interfold.Contracts.Models.Read.PublicSystemReadModel 100%
Interfold.Contracts.Models.Read.SetParentRequest 100%
Interfold.Contracts.Models.Read.SettingsCreateFieldRequest 100%
Interfold.Contracts.Models.Read.SettingsDescriptionRequest 100%
Interfold.Contracts.Models.Read.SettingsEncryptionRequest 0%
Interfold.Contracts.Models.Read.SettingsFieldReadModel 100%
Interfold.Contracts.Models.Read.SettingsImportRequest 100%
Interfold.Contracts.Models.Read.SettingsPushTokenRequest 0%
Interfold.Contracts.Models.Read.SettingsRelocateFieldRequest 0%
Interfold.Contracts.Models.Read.SettingsUpdateFieldRequest 0%
Interfold.Contracts.Models.Read.SettingsUsernameRequest 100%
Interfold.Contracts.Models.Read.TagAlterRequest 100%
Interfold.Contracts.Models.Read.TagPublicReadModel 100%
Interfold.Contracts.Models.Read.TagReadModel 100%
Interfold.Contracts.Models.Read.UpdateAlterFieldRequest 100%
Interfold.Contracts.Models.Read.UpdateAlterJournalRequest 100%
Interfold.Contracts.Models.Read.UpdateAlterRequest 100%
Interfold.Contracts.Models.Read.UpdateGlobalJournalRequest 100%
Interfold.Contracts.Models.Read.UpdatePollRequest 100%
Interfold.Contracts.Models.Read.UpdateTagRequest 100%
Interfold.Contracts.Models.VisibilityLevelExtensions 100% 100%
Interfold.Contracts.Models.VotePollData 100%
Interfold.Contracts.Operations.CommandEnvelope 100%
Interfold.Contracts.Operations.ConflictResult 100%
Interfold.Contracts.Operations.EntityRefs 100%
Interfold.Contracts.Operations.OperationIds 100%
Interfold.Contracts.PatchValue 70%
Interfold.Contracts.PatchValueJsonConverter 45.8% 33.3%
Interfold.Contracts.PatchValueJsonConverterFactory 100% 50%
Interfold.Contracts.PhoenixReplyPayload 100%
Interfold.Contracts.PhxArrayFrame 100%
Interfold.Contracts.PhxEndpointPayload 100%
Interfold.Contracts.PhxFrame 100%
Interfold.Contracts.PhxJoinPayload 100%
Interfold.Contracts.PollCommandResult 100%
Interfold.Contracts.PollDeletedSocketPayload 0%
Interfold.Contracts.PollSocketPayload 0%
Interfold.Contracts.Secrets.SecretEntry 0%
Interfold.Contracts.Secrets.SecretsStoreKey 100% 50%
Interfold.Contracts.Secrets.SecretsStoreKeys 100%
Interfold.Contracts.SettingsCommandResult 100%
Interfold.Contracts.SettingsFieldCommandResult 50%
Interfold.Contracts.SettingsFieldsUpdatedPayload 100%
Interfold.Contracts.SettingsSelfUpdatedPayload 0%
Interfold.Contracts.SettingsUsernameUpdatedPayload 0%
Interfold.Contracts.SingletonTaskName 75% 50%
Interfold.Contracts.SingletonTaskNames 100%
Interfold.Contracts.SocketBatchedAltersPayload 0%
Interfold.Contracts.SocketBatchedFrontsPayload 0%
Interfold.Contracts.SocketBatchedTagsPayload 0%
Interfold.Contracts.SocketEndpointProxyRequest 100%
Interfold.Contracts.SocketEndpointProxyResponse 100%
Interfold.Contracts.SocketJoinBatchedPayload 100%
Interfold.Contracts.SocketJoinInitPayload 100%
Interfold.Contracts.SocketJoinReconnectPayload 100%
Interfold.Contracts.SocketJson 100%
Interfold.Contracts.SocketReasonResponse 100%
Interfold.Contracts.SocketSelfReadModel 100%
Interfold.Contracts.SystemIdSocketPayload 100%
Interfold.Contracts.TagCommandResult 100%
Interfold.Contracts.TagDeletedSocketPayload 0%
Interfold.Contracts.TagSocketPayload 100%
Interfold.Contracts.UtcDateTimeConverter 87.5% 62.5%
Interfold.Contracts.UtcDateTimeOffsetConverter 26.6% 0%
Interfold.Contracts.Validation.ValidAlterIdAttribute 88.4% 85.7%
System.Text.RegularExpressions.Generated 71.4% 42.5%
Interfold.DatabaseBootstrap - 88.9%
Name Line Branch
Interfold.DatabaseBootstrap 88.9% 65.9%
Interfold.Contracts.Secrets.SecretsStoreKey 75% 50%
Interfold.Contracts.Secrets.SecretsStoreKeys 100%
Interfold.DatabaseBootstrap.NoOpDatabaseInitLogger 50%
Interfold.DatabaseBootstrap.PostgresReadinessOptions 100%
Interfold.DatabaseBootstrap.PostgresSeeder 73.9% 75%
Interfold.DatabaseBootstrap.PostgresSeedOptions 100%
Interfold.DatabaseBootstrap.PostgresSqlTemplates 96.1%
Interfold.DatabaseBootstrap.ScyllaCqlTemplates 100%
Interfold.DatabaseBootstrap.ScyllaReadinessOptions 0%
Interfold.DatabaseBootstrap.ScyllaSeeder 88.3% 58.3%
Interfold.DatabaseBootstrap.ScyllaSeedOptions 100%
Interfold.DatabaseBootstrap.SeedKeys 100% 68.1%
Interfold.DatabaseBootstrap.SqlEscape 100%
Interfold.Domain - 74.3%
Name Line Branch
Interfold.Domain 74.3% 53.1%
Interfold.Domain.Abstractions.CommandHandler 100% 75%
Interfold.Domain.Abstractions.IClusterEventBus 0%
Interfold.Domain.Abstractions.IdempotentCommandHandler<TPayload, TResult> 91.4% 80%
Interfold.Domain.Abstractions.IdempotentCommandHandler<TPayload, TResult> 43.7%
Interfold.Domain.Abstractions.ImportJobs.ImportJobItem 100%
Interfold.Domain.Abstractions.ImportJobs.ImportJobOutcome 100%
Interfold.Domain.Abstractions.INodeRoleContext 33.3%
Interfold.Domain.Abstractions.Repository.FriendNotificationTokens 100%
Interfold.Domain.Accounts.CreateLinkTokenCommandHandler 100%
Interfold.Domain.Accounts.CreateLinkTokenCommandResult 100%
Interfold.Domain.Accounts.UpdateUsernameCommandHandler 73.9% 50%
Interfold.Domain.Alters.AlterCommandFlow 96% 87.5%
Interfold.Domain.Alters.AlterCommandFlow 96% 87.5%
Interfold.Domain.Alters.AlterFieldProjection 100% 100%
Interfold.Domain.Alters.CreateAlterCommandHandler 86.6% 50%
Interfold.Domain.Alters.DeleteAlterCommandHandler 85% 50%
Interfold.Domain.Alters.UpdateAlterCommandHandler 66% 58.3%
Interfold.Domain.Auth.AuthenticateOAuthCommandHandler 95% 62.5%
Interfold.Domain.Auth.LinkOAuthIdentityCommandHandler 72.7% 62.5%
Interfold.Domain.Auth.LinkOAuthIdentityCommandResult 100%
Interfold.Domain.Auth.RecordAuthTokenCommandHandler 100%
Interfold.Domain.Auth.RecordAuthTokenCommandResult 100%
Interfold.Domain.Auth.RevokeAuthTokenCommandHandler 50%
Interfold.Domain.Auth.RevokeAuthTokenCommandResult 0%
Interfold.Domain.CommandSerialization 87.5% 50%
Interfold.Domain.EncryptionKey 75%
Interfold.Domain.FriendshipIdNormalization 100% 100%
Interfold.Domain.Friendships.AcceptFriendRequestCommandHandler 92.8% 50%
Interfold.Domain.Friendships.CancelFriendRequestCommandHandler 95.8% 100%
Interfold.Domain.Friendships.FriendshipCommandFlow 100% 83.3%
Interfold.Domain.Friendships.FriendshipCommandFlow 100% 83.3%
Interfold.Domain.Friendships.FriendshipCommandNormalization 100%
Interfold.Domain.Friendships.FriendshipEventBusExtensions 100%
Interfold.Domain.Friendships.RejectFriendRequestCommandHandler 91.6% 50%
Interfold.Domain.Friendships.RemoveFriendshipCommandHandler 91.6%
Interfold.Domain.Friendships.SendFriendRequestCommandHandler 83% 71.4%
Interfold.Domain.Friendships.SetFriendTrustCommandHandler 94.2% 100%
Interfold.Domain.Fronting.BulkUpdateFrontCommandHandler 18.7% 0%
Interfold.Domain.Fronting.DeleteFrontByIdCommandHandler 87.5% 75%
Interfold.Domain.Fronting.EndFrontCommandHandler 88.4% 50%
Interfold.Domain.Fronting.FrontingCommandFlow 68.2% 41.6%
Interfold.Domain.Fronting.FrontingCommandFlow.FrontByIdResolution 100% 100%
Interfold.Domain.Fronting.FrontingCommandFlow 68.2% 41.6%
Interfold.Domain.Fronting.FrontingEventBusExtensions 69.2% 83.3%
Interfold.Domain.Fronting.SetFrontCommandHandler 92.1% 78.5%
Interfold.Domain.Fronting.SetPrimaryFrontCommandHandler 19% 0%
Interfold.Domain.Fronting.StartFrontCommandHandler 81.4% 50%
Interfold.Domain.Fronting.UpdateFrontCommentCommandHandler 14.2% 0%
Interfold.Domain.Journals.AlterJournalCommandFlow 87.8% 50%
Interfold.Domain.Journals.AlterJournalCommandFlow<TCommand, TResult> 87.8% 50%
Interfold.Domain.Journals.AlterJournalCommandFlow 87.8% 50%
Interfold.Domain.Journals.AttachAlterToGlobalJournalCommandHandler 91.6%
Interfold.Domain.Journals.CreateAlterJournalEntryCommandHandler 85.1% 50%
Interfold.Domain.Journals.CreateGlobalJournalEntryCommandHandler 83.3% 50%
Interfold.Domain.Journals.DeleteAlterJournalEntryCommandHandler 93.3%
Interfold.Domain.Journals.DeleteGlobalJournalEntryCommandHandler 93.3%
Interfold.Domain.Journals.DetachAlterFromGlobalJournalCommandHandler 20.8%
Interfold.Domain.Journals.GlobalJournalCommandFlow 93.1% 50%
Interfold.Domain.Journals.GlobalJournalCommandFlow 93.1% 50%
Interfold.Domain.Journals.SetAlterJournalLockedCommandHandler 31.2%
Interfold.Domain.Journals.SetAlterJournalPinnedCommandHandler 31.2%
Interfold.Domain.Journals.SetGlobalJournalLockedCommandHandler 93.3%
Interfold.Domain.Journals.SetGlobalJournalPinnedCommandHandler 93.3%
Interfold.Domain.Journals.UpdateAlterJournalEntryCommandHandler 80.9% 42.8%
Interfold.Domain.Journals.UpdateGlobalJournalEntryCommandHandler 84.2% 40%
Interfold.Domain.Polls.CreatePollCommandHandler 88.8% 75%
Interfold.Domain.Polls.DeletePollCommandHandler 91.6%
Interfold.Domain.Polls.PollCommandFlow 97% 83.3%
Interfold.Domain.Polls.PollCommandFlow 97% 83.3%
Interfold.Domain.Polls.PollCommandValidation 100% 92.8%
Interfold.Domain.Polls.UpdatePollCommandHandler 81.2% 50%
Interfold.Domain.Settings.AddPushTokenCommandHandler 21.4% 0%
Interfold.Domain.Settings.CreateFieldCommandHandler 91.6% 50%
Interfold.Domain.Settings.DeleteAccountCommandHandler 14.8% 0%
Interfold.Domain.Settings.DeleteAvatarCommandHandler 38.4%
Interfold.Domain.Settings.DeleteFieldCommandHandler 38.4%
Interfold.Domain.Settings.ImportPkCommandHandler 100% 100%
Interfold.Domain.Settings.ImportSpCommandHandler 100% 100%
Interfold.Domain.Settings.RecoverEncryptionCommandHandler 20% 0%
Interfold.Domain.Settings.RelocateFieldCommandHandler 38.4%
Interfold.Domain.Settings.RemovePushTokenCommandHandler 23% 0%
Interfold.Domain.Settings.ResetEncryptionCommandHandler 30.7% 0%
Interfold.Domain.Settings.SettingsEventBusExtensions 100%
Interfold.Domain.Settings.SettingsFieldCommandFlow 88.8% 50%
Interfold.Domain.Settings.SettingsFieldCommandFlow 88.8% 50%
Interfold.Domain.Settings.SettingsIdempotentCommandFlow 61.1% 50%
Interfold.Domain.Settings.SettingsIdempotentCommandFlow 61.1% 50%
Interfold.Domain.Settings.SetupEncryptionCommandHandler 21.7% 0%
Interfold.Domain.Settings.UnlinkAppleCommandHandler 38.4%
Interfold.Domain.Settings.UnlinkDiscordCommandHandler 38.4%
Interfold.Domain.Settings.UnlinkEmailCommandHandler 93.7%
Interfold.Domain.Settings.UpdateDescriptionCommandHandler 89.4% 50%
Interfold.Domain.Settings.UpdateFieldCommandHandler 38.4%
Interfold.Domain.Settings.UploadAvatarCommandHandler 88.2% 50%
Interfold.Domain.Settings.WipeAltersCommandHandler 20.8% 0%
Interfold.Domain.Settings.WipeTagsCommandHandler 96.1% 100%
Interfold.Domain.Tags.AttachAlterToTagCommandHandler 88.8%
Interfold.Domain.Tags.CreateTagCommandHandler 60% 42.8%
Interfold.Domain.Tags.DeleteTagCommandHandler 93.3%
Interfold.Domain.Tags.DetachAlterFromTagCommandHandler 27.7%
Interfold.Domain.Tags.RemoveParentTagCommandHandler 93.3%
Interfold.Domain.Tags.SetParentTagCommandHandler 89.2% 62.5%
Interfold.Domain.Tags.TagCommandFlow 92.8% 50%
Interfold.Domain.Tags.TagCommandFlow 92.8% 50%
Interfold.Domain.Tags.TagCommandValidation 88.8% 60%
Interfold.Domain.Tags.UpdateTagCommandHandler 84.2% 50%
Interfold.Infrastructure - 74.8%
Name Line Branch
Interfold.Infrastructure 74.8% 60%
Interfold.Infrastructure.AuthHelper 100%
Interfold.Infrastructure.Coordination.FirebaseFCMService 18% 5%
Interfold.Infrastructure.Coordination.FrontNotifierBackgroundService 35.4% 0%
Interfold.Infrastructure.Coordination.InProcessEventBus 93% 90.9%
Interfold.Infrastructure.Coordination.InProcessEventBus.ChannelAsyncEnumera
ble.ChannelAsyncEnumerator
100% 83.3%
Interfold.Infrastructure.Coordination.InProcessEventBus.ChannelAsyncEnumera
ble.ChannelAsyncEnumerator
100%
Interfold.Infrastructure.Coordination.InProcessEventBus.ChannelAsyncEnumera
ble
100%
Interfold.Infrastructure.Coordination.InProcessEventBus.Subscription<TEvent
>
100%
Interfold.Infrastructure.Coordination.InProcessEventBus.TopicBag 62.5% 50%
Interfold.Infrastructure.Coordination.InProcessEventBus 93% 90.9%
Interfold.Infrastructure.Coordination.InProcessImportJobQueue 100% 50%
Interfold.Infrastructure.Coordination.NodeRoleContext 100%
Interfold.Infrastructure.Coordination.NullFCMService 14.2%
Interfold.Infrastructure.Coordination.NullSingletonTaskOwner 0%
Interfold.Infrastructure.Coordination.PrimaryOnlySingletonTaskOwner 50%
Interfold.Infrastructure.DependencyInjection.ConfigurationServiceCollection
Extensions
98.4% 95.6%
Interfold.Infrastructure.DependencyInjection.ConfigurationServiceCollection
Extensions
98.4% 95.6%
Interfold.Infrastructure.DependencyInjection.PersistenceRegistration 100%
Interfold.Infrastructure.DependencyInjection.ServiceCollectionExtensions 97.7% 85%
Interfold.Infrastructure.Persistence.ConcurrentProjection<TSource, TResult> 100%
Interfold.Infrastructure.Persistence.DatabaseTransientRetry 55.5% 34.6%
Interfold.Infrastructure.Persistence.DatabaseTransientRetry 55.5% 34.6%
Interfold.Infrastructure.InMemory - 77.3%
Name Line Branch
Interfold.Infrastructure.InMemory 77.3% 62.3%
Interfold.Infrastructure.InMemory.InMemoryIdempotencyStore 100%
Interfold.Infrastructure.InMemory.InMemoryRegionContext 100% 100%
Interfold.Infrastructure.InMemory.InMemorySecretsStore 0% 0%
Interfold.Infrastructure.InMemory.InMemoryServiceCollectionExtensions 70.4% 50%
Interfold.Infrastructure.InMemory.InMemoryStorageKeys 88.8% 87.5%
Interfold.Infrastructure.InMemory.Repository.InMemoryAccountRepository 87% 72.3%
Interfold.Infrastructure.InMemory.Repository.InMemoryAlterRepository 76.1% 67.1%
Interfold.Infrastructure.InMemory.Repository.InMemoryAlterRepository.AlterS
tate
100%
Interfold.Infrastructure.InMemory.Repository.InMemoryAuthTokenRevocationRep
ository
71.4% 25%
Interfold.Infrastructure.InMemory.Repository.InMemoryAuthTokenRevocationRep
ository.TokenRecord
100%
Interfold.Infrastructure.InMemory.Repository.InMemoryEncryptionStateReposit
ory
100% 25%
Interfold.Infrastructure.InMemory.Repository.InMemoryFriendshipRepository 77.9% 72%
Interfold.Infrastructure.InMemory.Repository.InMemoryFrontingRepository 75.8% 53%
Interfold.Infrastructure.InMemory.Repository.InMemoryImportOperationReposit
ory
89.4% 77.2%
Interfold.Infrastructure.InMemory.Repository.InMemoryJournalRepository 82.7% 68%
Interfold.Infrastructure.InMemory.Repository.InMemoryNotificationTokenRepos
itory
75.9% 66.6%
Interfold.Infrastructure.InMemory.Repository.InMemoryPollRepository 83.5% 64.7%
Interfold.Infrastructure.InMemory.Repository.InMemoryPollRepository.PollSta
te
100%
Interfold.Infrastructure.InMemory.Repository.InMemorySettingsFieldRepositor
y
32.9% 25%
Interfold.Infrastructure.InMemory.Repository.InMemoryTagRepository 76.7% 50%
Interfold.Infrastructure.InMemory.Repository.InMemoryTagRepository.TagState 100%
Interfold.Infrastructure.Postgres - 73.2%
Name Line Branch
Interfold.Infrastructure.Postgres 73.2% 54.3%
Interfold.Infrastructure.Postgres.AuthTokenRevocationRepository 73.3%
Interfold.Infrastructure.Postgres.PostgresConnectionFactory 100%
Interfold.Infrastructure.Postgres.PostgresHealthChecker 0% 0%
Interfold.Infrastructure.Postgres.PostgresIdempotencyStore 100% 50%
Interfold.Infrastructure.Postgres.PostgresMigrationService 85.6% 66.6%
Interfold.Infrastructure.Postgres.PostgresSecretsStore 25% 0%
Interfold.Infrastructure.Postgres.PostgresServiceCollectionExtensions 100%
Interfold.Infrastructure.Scylla - 70.7%
Name Line Branch
Interfold.Infrastructure.Scylla 70.7% 53.8%
Interfold.Infrastructure.Scylla.Fixups.HexColorFixupService 78.2% 60.7%
Interfold.Infrastructure.Scylla.Fixups.HexColorFixupService.ColorTable 100%
Interfold.Infrastructure.Scylla.Repository.AlterRowMappers 100% 100%
Interfold.Infrastructure.Scylla.Repository.FrontingRowMappers 100% 50%
Interfold.Infrastructure.Scylla.Repository.JournalRowMappers 100%
Interfold.Infrastructure.Scylla.Repository.ScyllaAccountRepository 75.7% 51%
Interfold.Infrastructure.Scylla.Repository.ScyllaAlterRepository 70.4% 58.9%
Interfold.Infrastructure.Scylla.Repository.ScyllaEncryptionStateRepository 88.4% 50%
Interfold.Infrastructure.Scylla.Repository.ScyllaExistsQueries 100%
Interfold.Infrastructure.Scylla.Repository.ScyllaFriendshipDenormalizedTabl
e
100%
Interfold.Infrastructure.Scylla.Repository.ScyllaFriendshipRepository 71.4% 51.9%
Interfold.Infrastructure.Scylla.Repository.ScyllaFrontingDenormalizedTable 89.3% 50%
Interfold.Infrastructure.Scylla.Repository.ScyllaFrontingRepository 84.4% 62.8%
Interfold.Infrastructure.Scylla.Repository.ScyllaFrontingRepository.Current
FrontRow
100%
Interfold.Infrastructure.Scylla.Repository.ScyllaImportOperationRepository 16.6% 5.5%
Interfold.Infrastructure.Scylla.Repository.ScyllaJournalRepository 76.8% 57.3%
Interfold.Infrastructure.Scylla.Repository.ScyllaNotificationTokenRepositor
y
10.8% 0%
Interfold.Infrastructure.Scylla.Repository.ScyllaPollRepository 82.9% 67.8%
Interfold.Infrastructure.Scylla.Repository.ScyllaSettingsFieldRepository 44% 27.7%
Interfold.Infrastructure.Scylla.Repository.ScyllaSettingsFieldRepository.Us
erFieldUdt
100%
Interfold.Infrastructure.Scylla.Repository.ScyllaSharedQueries 97.2% 58.3%
Interfold.Infrastructure.Scylla.Repository.ScyllaTagRepository 68.4% 45%
Interfold.Infrastructure.Scylla.Repository.TagRowMappers 100% 50%
Interfold.Infrastructure.Scylla.ScyllaConfigResolver 94.8% 58.3%
Interfold.Infrastructure.Scylla.ScyllaGlobalScope 100%
Interfold.Infrastructure.Scylla.ScyllaHealthChecker 0% 0%
Interfold.Infrastructure.Scylla.ScyllaKeyspaceResolver 91.6% 50%
Interfold.Infrastructure.Scylla.ScyllaMigrationService 78.6% 65.5%
Interfold.Infrastructure.Scylla.ScyllaScope 100%
Interfold.Infrastructure.Scylla.ScyllaScopeResolver 67.3%
Interfold.Infrastructure.Scylla.ScyllaScopeResolver 67.3%
Interfold.Infrastructure.Scylla.ScyllaServiceCollectionExtensions 100%
Interfold.Infrastructure.Scylla.ScyllaSessionProvider 100% 100%
Interfold.Infrastructure.Scylla.ScyllaUserRegistryRegionContext 76.7% 56.7%
Interfold.Infrastructure.Scylla.UserRegistryLookup 87.8% 70%
System.Text.RegularExpressions.Generated 89.4% 83.3%
Interfold.ServiceDefaults - 93.4%
Name Line Branch
Interfold.ServiceDefaults 93.4% 90%
Microsoft.Extensions.Hosting.Extensions 93.4% 90%
Microsoft.Extensions.Hosting.Extensions 93.4% 90%

Azyyyyyy added 2 commits July 21, 2026 20:32
…k rename

Two small cleanups that sit on top of the review-comment batches:

- Base/InterfoldControllerBase.HandleAvatarUploadAsync. Post-save tail
  (read-current → update-metadata → best-effort cleanup of the old Local
  bytes) was a byte-for-byte duplicate of RunAvatarMetadataChangeAsync,
  the helper Batch 5 extracted for the URL / delete flows. Route the
  multipart flow through the same helper via the same
  `c => updateMetadataAsync(avatarUrl, c)` closure trick
  HandleAvatarUrlUploadAsync uses. Drops ~15 lines and consolidates the
  cleanup rule so a future change to it (e.g. also purging External URLs,
  retry policy on the delete probe) only has to be made in one spot.
  RunAvatarMetadataChangeAsync's xml-doc is re-summarised to note it now
  covers all three avatar mutation flows (upload / URL / delete), not
  just the "no bytes uploaded" pair Batch 5 originally called out.

- AuthLinkController: rename RedirectWithSocketEventAsync → RedirectToClient.
  The old name misrepresented the method on two axes: (1) it's not async
  (returns IActionResult, no Task) and (2) it doesn't fire a socket event
  — it validates the caller-supplied redirect_uri and either Redirects or
  returns BadRequest(MissingRedirectUri). RedirectToClient reflects what
  the method actually does and matches the terse verb-noun style of Begin
  / Callback in the same controller. Updates the one call site and the
  prose reference in Begin's fail-fast comment.

Build clean (0 errors). Api.UnitTests: 380/380 pass on top of
3d0377a (tuple→bearing follow-up commit).
@Azyyyyyy
Azyyyyyy merged commit a10efa6 into develop Jul 21, 2026
1 check failed
@Azyyyyyy
Azyyyyyy deleted the dedup branch July 21, 2026 19:36
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