Table of Contents

Limits and Non-behaviour

The generated reference says what each class does. This page records the things it deliberately does not do, and the bounds that are fixed in code rather than configuration.

1. Configuration is a hard precondition, not a fallback

`lib/main.php` checks for `config.php` before the framework is allowed to exist. If it is missing and `install/` is present, the request is handed to the installer; if the installer is gone too, the request ends there.

The practical consequence: the application cannot boot in a degraded or read-only mode for inspection. There is no “load what you can” path. A deployment either has a complete `config.php` or does not run.

2. The supported-language set is seven codes, hard-coded in five places

The whitelist is literally `en, ar, zh, fr, ru, es, id`, and it appears five times in the tree:

Location Form
——
`lib/main.php:129` `$validLocales = ['en', 'ar', …]`
`lib/controller/TranslationController.php:40` `in_array($_GET['lang'], ['en', 'ar', …])`
`lib/controller/LocaleController.php:28` fallback when `available_locales()` is absent
`lib/dao/LanguageDao.php:13` documented in the class docblock
`install/include/setup.php:811` `$langOrder` for the installer's seed data

Adding a language therefore means five coordinated edits, and the installer's seed order can drift from the runtime whitelist.

Any locale with a region subtag is rejected. The sanitiser in `lib/main.php` is `preg_replace('/[^a-z]{2}/', '', strtolower($code))`, which only removes *runs of two or more* non-`a-z` characters. A single separator is left alone, so the value reaches the whitelist unchanged and fails:

Input After sanitiser Result
———
`en` `en` accepted
`EN` `en` accepted
`pt-br` `pt-br` rejected — `-` is a run of one
`pt_BR` `pt_br` rejected
`zh-Hans` `zh-hans` rejected
`en-us` `en-us` rejected

So `pt-BR` cannot be expressed, and adding it would need a real normalisation step rather than a longer whitelist.

3. One URL style at a time, decided by a single setting

`Dispatcher::dispatch()` branches on one configuration value, `rewrite_status`:

Both styles are always present in the code; only one is reachable per configuration. A new page type must be added to both the route table in `Bootstrap::defineRoutingRules()` and the query-parameter list in `lib/main.php`, or it will work in one URL style and 404 in the other.

`?download=` is the documented exception: it is handled before the SEO branch specifically so downloads survive either permalink setting.

4. `config.php` is required, and `config.sample.php` is the only template

There is no environment-variable fallback for the database credentials. `.env` is loaded through Dotenv when present, but the application's own settings live in `config.php`, which is derived from `config.sample.php`. See Requirements.

5. FrontHelper fails quietly

This is the most consequential non-behaviour in the codebase, and it is the facade's own documented decision.

`Scriptlog\Core\FrontHelper` is a deprecated facade over `Scriptlog\Service\FrontService`. Every data-access method delegates to the `FrontService` instance registered via `FrontHelper::setFrontService()`. When no service is registered, the methods return `null` or an empty array.

The inline SQL that used to back those methods was removed because it drifted from `FrontService`, used string interpolation, and one path was mysqli-only and broke on PDO. The fix was correct, but the chosen failure mode is silence. A theme calling `FrontHelper` before `Bootstrap` has run gets an empty result and renders a blank region with no error anywhere.

6. `tests` are extensive but not name-mapped to units

83 types have a test whose name suggests it covers them. 113 do not:

Layer Types without a matching test name
——
core 75
controller 17
dao 9
model 9
service 4

This is a name-based heuristic, not proof of a coverage gap: a test may cover a class under a different name, or through an integration test. But the shape is informative — `service` is the best-covered business layer by name (only 4 unmatched) while `core` is by far the largest gap. With 2,649 methods in the suite, the project clearly tests heavily; what it does not do is maintain a one-test-per-class correspondence.

7. `@todo` inventory is empty

There are zero `@todo` annotations in first-party code. The one hit in an earlier pass was inside a vendored HTMLPurifier shim. Either the backlog is tracked outside the source, or it is tracked in issues; it is not in the code.

8. Known inconsistencies, recorded rather than hidden