Commit Graph

7 Commits

Author SHA1 Message Date
Toutsu 2c9016a383 fix(shared,bot,discordbot): make club-picker Dapper calls AOT-safe (v3.9.2)
Deploy Telegram Bot / build-and-push (push) Successful in 7m18s
Deploy Telegram Bot / scan-images (push) Failing after 17s
Deploy Telegram Bot / deploy (push) Has been skipped
The 3.9.1 hotfix only repaired WizardDraftRepository, the most common
Dapper call in the wizard. The same AOT-unsafe CommandDefinition pattern
remained in 4 other places that the user hit immediately after the
deploy: the 'Choose visibility' wizard step triggers GetOwnerClubsAsync
when the user picks 'Публичная в витрине клуба' or 'Только для членов
клуба'. The wizard swallowed PlatformNotSupportedException, the
callback ack replied with '⚠️ Ошибка', and the next step never rendered.
Privacy 'didn't stick' from the user's perspective.

Two changes to fix the Discord side as well:

1. Switched GetOwnerClubsAsync / LoadClubsAsync / LoadManagerUserIdsAsync
   to the direct (sql, params) overload across TelegramWizardMessenger,
   DiscordWizardMessenger, DiscordWizardInteractionModule, and
   DiscordPermissionLookup — same pattern as the 3.9.1 fix.

2. Added Dapper.AOT module attribute ([module: Dapper.DapperAot]) and
   InterceptorsPreviewNamespaces to the DiscordBot project. The
   DiscordBot assembly was previously skipped by the AOT source
   generator, so even the direct-overload fix wouldn't have produced
   interceptors for the Discord-specific Dapper call sites. With this
   addition, the generator emits 3 DiscordBot-specific interceptors
   (DiscordWizardMessenger, DiscordWizardInteractionModule,
   DiscordPermissionLookup) and the AssemblyLoad ships with the right
   GmRelay.DiscordBot.generated.cs.

Also expanded the AOT shape regression tests to cover all 4
CommandDefinition sites + added a 'containingClass' parameter to
ExtractMethodBody to disambiguate the duplicated LoadClubsAsync names
in DiscordWizardInteractionModule.

Bumps: 3.9.1 -> 3.9.2.
2026-06-08 10:48:24 +03:00
Toutsu f796b7d1e4 fix(shared): make WizardDraftRepository AOT-safe (v3.9.1 hotfix)
Deploy Telegram Bot / build-and-push (push) Successful in 7m24s
Deploy Telegram Bot / scan-images (push) Failing after 4s
Deploy Telegram Bot / deploy (push) Has been skipped
Production regression in 3.9.0: Telegram bot silently dropped every update.
WizardDraftRepository.GetActiveAsync was called on every Telegram update
(via UpdateRouter -> TryGetWizardContext) and threw
System.PlatformNotSupportedException in NativeAOT, because Dapper.AOT 1.0.48
only generates interceptors for the (sql, object?) extension overloads and
NOT for the (CommandDefinition) overload. The runtime then fell back to
Dapper.SqlMapper.CreateParamInfoGenerator, which uses Reflection.Emit and
fails on AOT. TelegramBotService swallowed the exception, so /newsession
appeared to start but no button press reached the wizard and no session was
created.

Two related changes in WizardDraft:

1. Switched WizardDraftRepository.* from 'new CommandDefinition(sql, params,
   cancellationToken: ct)' to the direct 'connection.Query*(sql, params)'
   overload, matching the working pattern in JoinSessionHandler. Dapper.AOT
   now generates CommandFactory30<WizardDraft> + RowFactory17<WizardDraft> +
   QuerySingleOrDefaultAsync37<WizardDraft> for all four methods.

2. WizardDraft.CreatedAt/UpdatedAt/ExpiresAt are now DateTime (UTC) instead
   of DateTimeOffset. AOT RowFactory calls reader.GetDateTime() directly and
   does not perform DateTime -> DateTimeOffset conversion; the previous type
   raised InvalidCastException on the very first wizard_drafts query.

All 588/590 tests pass (2 pre-existing skipped, +5 new AOT regression tests
in WizardDraftRepositoryAotShapeTests). dotnet format clean.

Bumps: 3.9.0 -> 3.9.1.

Note: GetOwnerClubsAsync (Telegram/Discord), DiscordPermissionLookup, and
DiscordWizardInteractionModule.GetOwnerClubsAsync still use CommandDefinition
and will hit the same Reflection.Emit AOT failure when the user reaches the
PickClub visibility step. Follow-up in 3.9.2.
2026-06-08 10:02:59 +03:00
Toutsu 8f0f2ef7e7 refactor(wizard): move core to Shared, add IWizardMessenger contract (issue #112)
Moves the game-creation wizard state machine, view builder, and
platform-neutral contracts (callback data, step names, storage
exception, club option, step limits) from GmRelay.Bot to GmRelay.Shared.
Telegram continues to work through a new TelegramWizardMessenger
implementing IWizardMessenger and a WizardInteractionMapper that
converts Update → WizardInteraction. Wires the new platform column on
wizard_drafts (V032 migration) and switches chat/owner/thread/message
ids to TEXT so the same table can hold Discord snowflakes later.

- GameCreationWizard: now in Shared, takes IWizardMessenger +
  IWizardDraftRepository, dispatches on WizardInteraction.
- New IWizardMessenger contract with Edit/Send/Answer/GetOwnerClubs
  (returns string ids so Telegram longs and Discord snowflakes both
  fit).
- New WizardStepViewBuilder in Shared returns
  (text, IReadOnlyList<WizardAction>); TelegramWizardMessenger
  renders actions into InlineKeyboardMarkup via a new Bot-side
  ToInlineKeyboard helper.
- New WizardInteractionMapper in Bot (5-case test) converts Telegram
  Update to WizardInteraction.
- WizardDraft gains a Platform column; ChatId/MessageThreadId/OwnerId/
  DraftMessageId switched to string. V032 migrates existing rows and
  rebuilds the owner lookup index on (platform, owner_id).
- All existing wizard / create-session tests updated to the new
  contract (HandleInteractionAsync + WizardInteraction). Wizard
  callback-data format preserved.
- dotnet build clean, dotnet format --verify-no-changes clean, all
  101 wizard tests pass.
2026-06-05 16:23:20 +03:00
Toutsu a843c8b278 style: dotnet format pass on wizard code
PR Checks / test-and-build (pull_request) Successful in 8m12s
Deploy Telegram Bot / build-and-push (push) Successful in 5m37s
Deploy Telegram Bot / scan-images (push) Successful in 1m34s
Deploy Telegram Bot / deploy (push) Successful in 42s
2026-06-04 15:33:25 +03:00
Toutsu 186492a18d test(wizard): add submit, cleanup, router delegation tests 2026-06-04 10:33:50 +03:00
Toutsu 2819786f91 test(wizard): add wizard tests + refactor to IWizardDraftRepository
- Extract IWizardDraftRepository interface for testability (NSubstitute cannot
  mock sealed classes; the codebase uses fake-style doubles instead).
- Add step-transition, pool-slot, validation, cancel/back, and render-shape tests
  using FakeWizardDraftRepository and FakeWizardMessenger.
- Fix wizard payload persistence bug: HandleCallbackAsync and HandleTextAsync
  now call SavePayload after ApplyChoice/ApplyText mutations, so subsequent
  LoadPayload calls see the user's progress. Previously, local WizardPayload
  mutations were discarded and the wizard reset on every step.
- CommitCurrentPoolSlot now auto-creates a slot via EnsureCurrentPoolSlot when
  one is missing, so the PoolSlotCapacity → waitlist click is recoverable
  even if the user lands on the step without a slot.
2026-06-04 09:53:15 +03:00
Toutsu 384887a862 test(wizard): add WizardDraftRepository integration tests 2026-06-04 08:13:22 +03:00