# Fallback Audit - 2026-04-22

Policy source: `requirements/environment.md`

Hard constraints include:
1) No fallbacks unless explicitly listed
2) Fail fast on missing/invalid data paths
3) Show explicit errors at point of detection

## Confirmed fallback behavior (policy violations)

1. `feca_mailshots_plugin/src/Application/TemplateRenderer.php:26`
- `strict_variables` is `false`, so missing Twig variables silently render as empty values.
- This is a runtime data fallback.

2. `feca_mailshots_plugin/src/Application/DataSourceService.php:175-187`
- `listSchemas()` catches `Throwable` and silently continues with only configured members schema.
- Explicitly documented as fallback in comment.

3. `feca_mailshots_plugin/src/Admin/MailshotsAdminPage.php:314-370`
- `getTemplateHtmlValue()` has multiple layered value fallbacks and swallow-catch blocks.
- This is intentional resilience, but still fallback behavior.

4. `feca_mailshots_plugin/src/Admin/MailshotsAdminPage.php:659-663`
- Save path catches read failure and falls back to `templateJodit.value`.

5. `feca_mailshots_plugin/src/Admin/MailshotsAdminPage.php:555-559`
- Token load failure clears token list and continues UI instead of hard erroring.

6. `feca_mailshots_plugin/src/Admin/MailshotsAdminPage.php:595-597`
- PDF asset list failure is replaced with an inline placeholder option and flow continues.

7. `feca_mailshots_plugin/src/Admin/AdminRequestHelpers.php:48-66`
- `uploadedFileToBase64(..., $fallback)` keeps prior base64 value when upload absent/invalid.

8. `feca_mailshots_plugin/src/Admin/DataSourcesAdminPage.php:182-186`
- DSL builder auto-selects `fenedgec_members` when present.
- This is auto-default selection fallback.

9. `feca_mailshots_plugin/src/Admin/MailshotTestAdminPage.php:54-56`
- Auto-selects first mailshot if request has no `mailshot_id`.

10. `feca_mailshots_plugin/src/Infrastructure/PhpImapAppender.php:21,24,25`
- Defaults IMAP port/folder/flags to `993` / `Sent` / `/imap/ssl` if missing.

11. `feca_mailshots_plugin/src/Repository/MailCredentialRepository.php:63-68`
- Empty submitted passwords are replaced with existing stored passwords.

12. `feca_mailshots_plugin/src/bootstrap.php:11-17`
- Missing/invalid setup option values become empty strings and only fail later when DB router validates config.
- Not silent success, but still fallback acquisition behavior.

## Defaulting that should be reviewed for strict mode

1. `feca_mailshots_plugin/src/Application/AttachmentService.php:29`
- MIME defaults to `application/octet-stream`.

2. `feca_mailshots_plugin/src/Application/PdfAssetService.php:29-31`
- MIME defaults to `application/octet-stream`; justification defaults to `in-place`; width/height default to zero.

3. `feca_mailshots_plugin/src/Admin/AttachmentsAdminPage.php:65`
- Edit form defaults MIME to `application/octet-stream`.

4. `feca_mailshots_plugin/src/Admin/PdfAssetsAdminPage.php:65-68`
- Edit form defaults MIME/width/height/justification values.

5. `feca_mailshots_plugin/src/Admin/ProfileAdminPage.php:88,99,102,103,129,136,139,140`
- SMTP/IMAP ports and IMAP folder/flags are defaulted in UI and request extraction.

6. `feca_mailshots_plugin/src/Admin/SetupAdminPage.php:70,93,120`
- DB port defaults to `3306` in UI and request extraction.

## Notes

- Missing Twig dependency is currently a hard error (`TemplateRenderer.php:15-17`) and is compliant with the standing instruction.
- This audit is code-focused and excludes test-only scaffolding.

## Suggested strict/no-fallback remediation order

1. Enforce Twig strict variable failures (`strict_variables => true`) and surface template variable errors in UI.
2. Remove silent catches in `MailshotsAdminPage` template/token/asset loaders; show local hard error and block save.
3. Remove `DataSourceService::listSchemas()` silent fallback catch; return explicit error path.
4. Remove auto-selections (first mailshot / default schema); require explicit user choice.
5. Remove implicit IMAP/SMTP/asset defaults; require explicit configured values.
6. Replace password-preserve-on-empty with explicit "unchanged" intent flag instead of implicit fallback.
