# TFB v1.7.1 Performance + Transition Report

Date: 2026-08-18

## Transition decision
- `transition_effect_ms` accepts 0..5000 inclusive.
- Default remains 300ms.
- 5001 is rejected in the existing admin validation flow.
- The setting is persisted for product/config compatibility, but no transition sleep runs inside the webhook. The next-question edit is the visible transition surface.

## Measurement method
- `perf_trace` is opt-in through `app.perf_trace=true` or `TFB_PERF_TRACE=1`.
- One compact JSON line/request is written to `storage/logs/perf.log`; 512KB cap and three rotations.
- No update body, user text, token, password or webhook secret is written.
- Local test: PHP built-in server, local MariaDB, local mock Telegram, 30 samples/path. These numbers measure TFB-controlled overhead; they are not production Telegram RTT claims.

## Before/after
| Path | BEFORE total p50/p95 ms | AFTER total p50/p95 ms | BEFORE ACK p50/p95 ms | AFTER ACK p50/p95 ms | DB queries | TG calls |
|---|---:|---:|---:|---:|---:|---:|
| Admin main menu | 4.924 / 7.296 | 3.923 / 5.105 | 4.894 / 7.266 | 3.270 / 4.502 | 13→8 | 2→2 |
| Admin tests list | 5.053 / 5.855 | 4.188 / 4.795 | 5.026 / 5.821 | 3.096 / 3.735 | 15→10 | 2→2 |
| Student option→next | 111.727 / 113.122 | 8.360 / 9.753 | 111.679 / 113.069 | 3.981 / 4.453 | 22→21 | 3→2 |

## Bottlenecks and fixes
1. `QuizFlowHandler::processAnswer()` used a blocking transition sleep and an extra analysis edit: removed from webhook; one Telegram call removed.
2. Student option ACK happened after answer/render: ACK now occurs after dedupe and ownership/state validation, before mutation/render.
3. Admin ACK happened after controller/render: ACK now occurs after dedupe/admin auth and before cleanup/render.
4. Idle admin callbacks performed unnecessary prompt-cleanup queries: cleanup now runs only in an admin waiting state.
5. Repeated same-request user lookup: `UserRepository` memoizes `findByTelegramId()` and invalidates on touched mutations.

## Latency math
Normal non-completion callbacks now use two sequential Telegram API calls: ACK + one edit. With host Telegram RTT around 50–150ms, the network floor is approximately 100–300ms plus PHP/DB overhead. Local measured TFB overhead is about 4ms admin and 8ms student for the tested fixtures. Telegram RTT, host PHP worker scheduling, remote DB latency and occasional 429 remain external variables; verify on the real host.

## Safety/regression
- Duplicate student option callback: one answer and one edit; each delivery ACKed.
- Duplicate admin callback: one menu edit; each delivery ACKed.
- 17 scripts, 596 assertions, zero failures.
- Production perf trace default: OFF.
- No schema migration in this patch; schema revision remains 1.7.0 while app/package version is 1.7.1.

## Acceptance checklist

### M1 Transition
T1 PASS · T2 PASS · T3 PASS · T4 PASS

### Perf discipline
P1 PASS · P2 PASS · P3 PASS · P4 PASS · P5 PASS

### Perf outcomes
S1 PASS · S2 PASS · S3 PASS · S4 PASS · S5 PASS · S6 PASS · S7 PASS

### Correctness
C1 PASS · C2 PASS · C3 PASS · C4 PASS · C5 PASS · C6 PASS · C7 PASS

### Documentation
D1 PASS · D2 PASS · D3 PASS · D4 PASS · D5 PASS · D6 PASS · D7 PASS · D8 PASS · D9 PASS

### Agent proof
Z1 PASS · Z2 PASS · Z3 PASS · Z4 PASS · Z5 PASS

## Minimal code files
- `src/Controllers/Admin/AdminSettingsController.php`
- `src/Support/AdminEditableSettings.php`
- `src/Engines/Flow/QuizFlowHandler.php`
- `src/Controllers/Admin/AdminCallbackDispatcher.php`
- `src/Bot/UpdateRouter.php`, `WebhookPipeline.php`, `TelegramClient.php`
- `src/Core/Database.php`
- `src/Repositories/UserRepository.php`
- `src/Logging/FileLogger.php`, `PerfTrace.php`
- `public/index.php`, `config/app.example.php`

## Documentation files updated
README, CHANGELOG, PROJECT_STATUS, STATUS.json, AGENT_HANDOFF, OPERATIONS, ARCHITECTURE, PRODUCT_RULES, DB_SCHEMA, CODING_STANDARDS, CODING_GUIDE, KNOWN_ISSUES, PHASES, ADMIN_GUIDE, LOGGING_AND_DIAGNOSTICS_FA, RELEASE_NOTES_FA, and this report.

## Persian owner smoke
1. تنظیم افکت را روی ۰، ۸۰۰ و ۵۰۰۰ ذخیره کنید؛ ۵۰۰۱ باید رد شود.
2. یک منوی inline ادمین را چند بار باز کنید؛ محتوا و spinner باید درست باشند.
3. یک گزینه دانش‌آموز را دوبار سریع بزنید؛ فقط یک answer ثبت شود.
4. با افکت روشن به سؤال بعد بروید؛ webhook نباید چند ثانیه مکث کند.
5. `/start`، `/help` و `/admin` را تست کنید.
6. برای اندازه‌گیری موقت perf trace را روشن و `storage/logs/perf.log` را بررسی کنید؛ سپس خاموش کنید.
7. Health باید `schema_ok=true` و `pending_migrations=0` نشان دهد.
