# Bug fix — Issue #1577: unregistered Code Tracker types were persisted and generated Event Viewer warnings ## Symptom The modern Code Tracker BFF accepted arbitrary integer values in the `type` field. A crafted create request with `type: 6` returned HTTP 200, persisted the unknown type, and the following list/delete requests dereferenced missing system metadata. PHP 8.3 recorded ten `E_WARNING` rows in Event Viewer from `tlCodeTracker.class.php:116,120,124,559,560`. Entry points: - API: `http://localhost:8082/api/codetracker/index.php` - Screen: `http://localhost:8082/gui/templates/codetracker/codetrackerView.html` ## Reproduction before the fix 1. Authenticate as `admin` with `codetracker_management` right 51. 2. POST `{"name":"repro-1577-unknown","type":6,"cfg":""}` to the API root. 3. Request the collection and the returned tracker detail. 4. Delete the temporary tracker and inspect Event Viewer. Measured result: create, list, and delete all returned HTTP 200. Type 6 was persisted even though the registered enabled systems were only type 1 (stash) and type 200 (github). Event Viewer contained ten new warnings generated by the legacy lookups; the browser showed no JavaScript exception. ## Root cause chain 1. The BFF create route previously applied `intval()` to any submitted type but never checked it against `tlCodeTracker::getSystems()`. 2. The update route had the same lossy coercion and also did not distinguish an omitted partial-update type from an explicitly supplied value. 3. `tlCodeTracker::create()` and `update()` persisted the unchecked integer. 4. Serialization and delete handling then indexed `$systems[$type]` and `$implementations[$type]` without a presence guard. Missing metadata produced the warnings instead of a client error. 5. The structured 400 response had no UI mapping, so adding BFF validation also required a localized client message. **Why it breaks now:** the REST create/update surface was added during the Code Tracker modernization without the validation that the normal type selector makes implicit in the browser. Direct API clients could bypass that UI constraint. **Blast radius:** authenticated managers could create an unusable row or change a valid row to an unusable type. Anonymous and view-only requests remained protected by the existing 401/403 gates; those checks execute before the new type validation. ## Fix approach The BFF is the trust boundary, so validation was added there rather than relying on the browser type selector. - `api/codetracker/index.php:82` requires request bodies to be top-level JSON objects. Scalar, list, and malformed bodies return HTTP 400 `{"status":"error","code":"invalid_body"}` instead of reaching array access or producing a PHP error. - `api/codetracker/index.php:91` accepts only JSON integers or canonical signed decimal strings. Booleans, floats, null, objects, arrays, and strings with trailing characters are rejected before lossy coercion. - `api/codetracker/index.php:102` checks the normalized value against `getSystems(['status' => 'enabled'])`. Unknown and disabled systems return HTTP 400 with `code=invalid_type` and the rejected integer. - `api/codetracker/index.php:200` validates create input before persistence. - `api/codetracker/index.php:233` validates an explicitly supplied update type before loading or changing the tracker. An omitted type remains a valid partial update and retains the stored type. - `gui/templates/codetracker/codetrackerView.html:397` maps `invalid_type` to `ct.msg.invalidType`; the key exists in all 10 modern locale bundles. Authorization ordering is unchanged: same-origin, authentication, page read rights, and management rights all run before body/type validation. ### Alternatives considered and rejected - **Harden only `tlCodeTracker::getByID()`/serialization:** this would suppress warnings but still persist an invalid type and leave list/delete behavior ambiguous. The BFF must reject invalid state at ingress. - **Accept any registered type, including disabled systems:** disabled systems are not usable and should not be creatable through the API. Validation uses the enabled-system set. - **Coerce with `intval()` before validation:** values such as `true`, `1.5`, or `1junk` can alias a registered integer. Raw values are normalized strictly first. - **Treat omitted PUT type as zero and reject it:** that would break the existing rename/config-only partial update. Presence is checked separately. - **Return a hardcoded English PHP error:** violates the BFF i18n contract and would expose implementation wording in the modern screen. ## Verification - `php -l api/codetracker/index.php` and `git diff --check`: clean. - Inline JavaScript parses successfully; all 10 locale bundles pass `python3 -m json.tool`. - Registered types 1 and 200 retain create, list, detail, update, and delete behavior. Type transitions `1→200` and `200→1` pass. - Unknown, disabled, malformed, boolean, float, null, and trailing-text type values return HTTP 400 without persistence. - Omitted PUT type retains the stored type. - Anonymous invalid create returns 401; a temporary user holding only `codetracker_view` receives 403 on create and stored-token connection paths. - The create modal displays `Code Tracker type 999 is unknown.` and remains open; the collection remains empty. - Event Viewer WARNING/ERROR count remains exactly 10, all created by the pre-fix reproduction. Rows with `id > 11` at levels 2/4: 0. - Regression suite in `tmp/TLU_Test_Cases.md`: 8/8 PASS. ## Screenshots Before the fix, Event Viewer shows the ten PHP warnings produced by create, list, and delete operations against the unknown tracker type: ![Issue 1577 before fix — Event Viewer warnings](issue-1577-before.png) After the fix, the create modal keeps the user's input and displays the localized structured error; the unknown tracker is not added to the table: ![Issue 1577 after fix — localized invalid type error](issue-1577-after.png) ## Files changed - `api/codetracker/index.php` — request-shape and enabled tracker-type guards. - `gui/templates/codetracker/codetrackerView.html` — structured error rendering. - `gui/templates/i18n/{de,en,es,fr,it,ja,pt,ro,ru,zh}.json` — localized message. - `tmp/TLU_Test_Cases.md` — Issue #1577 regression suite. - `CHANGELOG` and this Wiki/docs mirror. ## Result Issue #1577 is fixed on `fix/issue-1577` in commits `4497f11bb` (fix) and `f25761c01` (regression suite). The original warning-producing path is rejected before persistence, normal registered-type behavior is preserved, and no new Event Viewer warning was generated.