# Quaeriva release checklist

Applies to the version in `VERSION`. The historical release plan is archived at
`docs/archive/PLAN-RELEASE.md`; this file is the current per-release gate.

## Source and packaging

Packaging is decided by `bin/package.php`, not by reading this list. The script
refuses to build when anything excluded would ship — a checklist a person reads
is not a control, and a debug script that dumped API output once survived a
declared "final cleanup".

- [x] `VERSION` is the single release source.
- [x] Local database credentials belong in untracked `config/database.local.php`.
- [x] No hard-coded `/ask` or other installation folder is required.
- [x] `config/site.local.php` and `.quaeriva-installed.lock` are ignored local/runtime state, not source editions.
- [x] Project-root `.htaccess` denies `.git/` and `.github/` when a full source checkout is deployed there.
- [x] Apache 2.4 project-root smoke: GET/POST `/admin` reaches the panel without a trailing-slash redirect; protected source/config/test/doc paths return 403.
- [x] Text source files are valid UTF-8 and contain no literal NUL bytes.
- [x] Historical internal plans live under `docs/archive/`, not as cryptic root-level source files.
- [x] Public/admin/API/internal URLs use centralized base-path helpers.
- [x] `php bin/package.php --check` reports no unexpected inclusion.
- [x] `php bin/package.php` builds the archive; extract it and re-run verification **against the extracted copy** in a temporary directory outside the project, then delete that extraction.

### Never ships

`config/database.local.php` · `.env` · `storage/` · `tests/` · `docs/` · `dist/`
· any `*.zip` or `*.log` · any `tmp_*` file · the installation lock.

### Must ship

`.htaccess` · `admin/.htaccess` · `public/.htaccess` · `install/.htaccess` · `storage/.htaccess`
· `.env.example` · generated `config/release-manifest.json` — these enforce routing/security,
protect runtime data, document configuration, and identify the exact packaged build.

## Non-database verification

- [x] Bootstrap/config tests.
- [x] Locale/translation tests.
- [x] Public UI and auth route tests.
- [x] Administration contract and UX tests.
- [x] SEO tests.
- [x] Core Q&A Plus static contract tests.
- [x] API-token/write contract tests.
- [x] Notification/acceptance contract tests.
- [x] Search/audit/widget completion contract tests.
- [x] Security/taxonomy hardening contract tests.
- [x] PHP syntax lint over all PHP files.
- [x] Search integration passes with the MySQL session in `NO_BACKSLASH_ESCAPES` mode, including literal `%`, `_`, `|`, and backslash terms.
- [x] The service-exception contract reports zero untranslated user/operator validation exceptions; documented internal whitelist invariants are the only exclusions.
- [x] Language, plugin, theme, and widget audit mutations expose semantic actions plus escaped before/after snapshots.
- [x] Shared public breadcrumbs have one accessible RTL/LTR layout with visual separators on non-home routes.
- [x] Managed primary-menu ordering persists through the admin reorder form and is consumed by the public header.
- [x] Navigation polish contract coverage (`tests/Public/task88.php`).

## Production-readiness integration gates

- [x] Disabled plugins are not required/executed during discovery.
- [x] Safe Mode prevents plugin PHP execution.
- [x] Plugin `requires` compatibility is enforced before PHP execution.
- [x] Runtime plugin activation reads the same `plugins.active` state managed by Administration.
- [x] Core hook contract covers registration/question/answer/comment lifecycle events.
- [x] Translation catalog test checks placeholder parity.
- [x] Runtime literal translation-key coverage test passes for shipped Arabic and English catalogs.
- [x] One widget failure is isolated from sibling widgets.
- [x] Theme activation enforces `min_core` and enabled-language direction requirements.
- [x] Critical UI/runtime paths have an `mbstring`-independent UTF-8 fallback.
- [ ] Browser smoke: plugin enable/disable changes behavior on the next request without PHP/FPM restart.
- [ ] Browser smoke: language-disable blocker and success/error alerts are visible in Arabic and English.
- [ ] Target-host smoke: Safe Mode suppresses every plugin on LiteSpeed/shared hosting.

## MySQL-required verification

Run locally with PDO MySQL or require a green GitHub Actions workflow. The workflow is configured, but it is not evidence until it has actually run green on the exact commit/tag:

- [ ] GitHub Actions strict MySQL matrix is green with **zero skipped** task suites on the exact release commit.

- [x] `php tests/Database/task3.php`
- [x] `php tests/Security/task4.php`
- [x] `php tests/Questions/task5.php`
- [x] `php tests/Api/task8.php`
- [x] `php tests/Install/task9.php`
- [x] `php tests/Admin/task15.php`
- [x] `php bin/migrate.php`
- [x] `php bin/admin-smoke.php --write`

## Language and RTL/LTR

- [x] Public locale persists without `/ar`, `/en`, or persistent `?lang=` content variants.
- [x] Public/admin defaults are independent.
- [x] Arbitrary registered locale codes, fallback, direction, and translation overrides are supported.
- [x] Translation JSON import/export preserves stable keys/placeholders.
- [x] Search controls follow interface direction.
- [x] User-content fields can use automatic content direction.
- [x] Technical email/URL/token fields remain direction-safe.
- [x] Browser check: Arabic RTL at 320/375/768/1024/1440.
- [x] Browser check: English LTR at 320/375/768/1024/1440.
- [ ] Browser check: one additional LTR and one additional RTL registered language.
- [x] No horizontal overflow or console errors at supported widths.

## Q&A and community

- [x] Topics: create a discussion and moderator-only announcement (local lifecycle coverage in `tests/Community/task86.php`).
- [x] Topics: add a comment, verify page 2 after more than 50 comments, and preserve the page after comment/report redirects (local lifecycle coverage).
- [x] Topics: lock rejects new comments server-side; pin sorts first; reports appear in the existing reports screen; hide removes the topic from public listings (local lifecycle coverage).
- [x] Topics: moderator/admin create, edit, publish, hide, pin, unpin, lock, unlock, and delete actions are audited with before/after state (local lifecycle coverage).
- [x] Topics: authenticated detail pages render after creation and after report-state lookups; the `/d` route has a regression contract for native PDO placeholder safety.

- [x] Ask Question performs a real authenticated write.
- [x] Ask renders all database categories; category selection can synchronize content language without hiding other valid taxonomy.
- [x] Missing Unicode tags can be created on Enter without submitting the question, including IME-safe input.
- [x] Duplicate suggestions are bounded and rate limited.
- [x] Answers, answer comments, toggle votes, accepted answer, and question/answer/comment reports are wired.
- [x] Public question-level comment composer is removed; legacy question comments remain moderatable.
- [x] Self-voting is rejected.
- [x] Question/category/tag follows are wired.
- [x] Member notifications and preferences are wired.
- [x] Administrator event alerts support internal/email/Telegram channels.
- [x] Contact messages are stored and administrable.

## Membership and operations

- [x] Registration can be enabled/disabled.
- [x] Optional email verification is configurable.
- [x] PHP mail transport is optional and configurable.
- [x] Password reset flow is available.
- [x] Login/register/recovery writes are rate limited.
- [x] Maintenance mode is configurable.
- [x] Profile editing and public member activity are available.
- [x] System diagnostics do not expose database secrets.

## Administration

- [x] Questions, answers, comments, categories, tags, users, reports, messages, and languages use compact management tables/actions.
- [x] Existing root categories can be converted to children.
- [x] Category cycles and mixed-language parent chains are rejected.
- [x] User activate/suspend/ban/delete actions exist with final-admin protection.
- [x] Settings are separated into General/Membership/Community/Maintenance/Mail/Notifications/SEO tabs.
- [x] Audit/moderation history is administrator-only.
- [x] Published homepage layout/widgets are connected to the public renderer.
- [x] Community insight widgets and the optional homepage advertising widget are registered and bounded.
- [x] Advertising management is administrator-only and covers header/footer/homepage/after-question/between-answer placements.
- [x] Database upgrades can be initiated from Administration when runtime-compatible, use the same locked upgrade service as CLI, and do not block safe writes solely for non-blocking pending migrations.
- [x] Advertising supports a separate trusted provider head code plus per-placement desktop/tablet/mobile visibility.

## API

- [x] Read question list/detail.
- [x] List filters include category/tag/search/answered/date/member/locale/pagination.
- [x] Bearer tokens are stored hashed and scoped.
- [x] Question/answer/comment/vote/accept/follow/report mutations are implemented.
- [x] `/notifications` and `/me` are implemented for authorized requests.
- [x] JSON responses use the stable envelope and security headers.
- [x] `/api/v1/auth/*` is documented as outside the 0.7 API contract rather than as an implemented workflow.

## Security

- [x] Browser mutations use CSRF.
- [x] Server-side authorization is enforced.
- [x] Prepared statements are used for user-controlled database values.
- [x] Passwords and API tokens are never stored raw.
- [x] Rate limits cover authentication and public/API community writes.
- [x] Administration is noindex and frame-protected.
- [x] Public HTML/API responses include baseline security headers.
- [x] User rich text escapes raw HTML, rejects unsafe URL schemes, and marks external community links as UGC/nofollow.
- [x] Raw provider/AdSense code is available only in administrator advertising settings; PHP tags are rejected.
- [x] Audit rows hash IP values instead of storing raw addresses.
- [ ] Production HTTPS/HSTS and host rewrite rules verified on target hosting.

## SEO

- [x] `/q/{slug}` is canonical and legacy detail URLs redirect permanently.
- [x] `/questions` is not a duplicate indexable home page.
- [x] Search is `noindex,follow`.
- [x] `robots.txt` and sitemap are generated.
- [x] Sitemap excludes unpublished/noindex questions.
- [x] QAPage JSON-LD is conditional on eligible answered questions and carries accepted/suggested answers and author profile URLs.
- [x] Public member profiles expose ProfilePage structured data.
- [x] Category/tag SEO fields and sitemap routes are supported.
- [x] Topic `/d/{slug}` pages emit canonical, multilingual hreflang alternates, `DiscussionForumPosting`, and comment interaction counts; legacy topic `/t/{slug}` links redirect permanently.

### Batch 6 gates

- [x] Static contracts cover configured-site-name substitutions in mail subjects, From-name fallbacks, notifications, profile/meta copy, and the allowlisted engine-name labels.
- [x] Category pages expose questions and discussions separately; tag pages remain questions-only.
- [x] Sitemap question, topic, category, and tag queries share the 45,000-URL cap, and topic `lastmod` uses latest activity.
- [ ] Browser verification confirms renamed-site rendering in Arabic RTL and English LTR at 320/375/768/1024/1440.
- [ ] MySQL/MariaDB verification confirms the write flow and extracted-package behavior on the release commit.
- [ ] Sitemap index with paged child sitemaps is implemented; this is intentionally deferred and documented in `docs/KNOWN-WORK-BATCH6.md`.

## Final release evidence

Development checks do not replace target-host verification. Before a public GitHub tag, require a green MySQL CI run and record at least one successful install/upgrade on a clean disposable database.
