# Changelog All notable changes to `indifferentketchup/codex` are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [0.3.0] — 2026-05-04 Adds IP-address redaction to the PZ redactor, a new `ErrorContextAnalyser` for surrounding-context surfacing, the `tools/pz-analyzer/` Python toolset (pre-production Qwen-driven research analyser and production-bound deterministic classifier), and a parser fix for the PZ B42 log shape that was silently breaking level/prefix attribution since The Indie Stone dropped the per-line `t:` field. New public API surface across the redactor and the analyser-side classes makes this a minor bump rather than a patch. ### Added - **IP redaction in `ProjectZomboidRedactor`** (`src/Util/ProjectZomboid/ProjectZomboidRedactor.php`) — fourth pass that scrubs IPv4 (strict 0-255 octets, optional `:port` suffix) and IPv6 (full, abbreviated, bracketed-with-port, IPv4-mapped) addresses, replacing them with the literal `[REDACTED_IP]`. New public API: `IP_REPLACEMENT`, `IPV4_REGEX`, `IPV6_REGEX` constants and a `redactIpAddresses(bool)` toggle (defaults on, mirroring the existing three category toggles). Pattern-disjoint from the Steam-ID → name → coordinates chain; runs first by convention. Strict regexes plus `filter_var()` validation prevent false positives on PZ timestamps and PHP / Java scope ops. 20 new unit tests across two files (`ProjectZomboidRedactorIpv4Test.php`, `ProjectZomboidRedactorIpv6Test.php`). - **`ErrorContextAnalyser`** (`src/Analyser/ProjectZomboid/ErrorContextAnalyser.php`) — generic-purpose analyser that walks `Entry[]` once and emits one `ErrorContextProblem` per ERROR / WARNING entry with up to `CONTEXT_BEFORE` (20) entries of leading context and `CONTEXT_AFTER` (20) entries of trailing context. Overlapping windows clip to `lastEmittedIndex + 1` so no Entry appears in two context arrays; emission caps at `HIT_CAP` (500) with a single `ErrorContextTruncatedInformation` appended when reached. Standalone — not auto-registered to any existing Log subclass's `getDefaultAnalyser()`; consumers wire it in explicitly. Companion classes `ErrorContextProblem` and `ErrorContextTruncatedInformation` under `src/Analysis/ProjectZomboid/`. 3 unit tests, 134 assertions. - **`tools/pz-analyzer/`** — Python toolset adjacent to the library (not part of the Composer package's autoload surface). `pz_redact_all.sh` is a one-shot Docker wrapper that runs the PHP redactor over `.scratch/pz/Logs/` and produces a gitignored `.scratch/pz/Logs.redacted/` directory. `pz_error_analysis.py` is a developer-facing Qwen-backed pre-production analyser that calls a local OpenAI-compatible endpoint to classify residual log shapes the deterministic side hasn't yet captured. `pz_parser.py` + `pz_classify.py` are the production-bound deterministic-only counterpart: pure parser module with mod attribution, file:line extraction, cause-chain unwinding, engine-noise tagging, and a two-level signature scheme (`pattern_id` + `signature`), plus a stdlib-only orchestrator that walks the redacted directory and emits a JSON report. 32 Python unit tests across three files, 16 synthetic fixtures. - `docs/superpowers/specs/2026-05-04-pz-deterministic-classifier-design.md` — design contract for `pz_parser.py` / `pz_classify.py`. The PHP-side `ErrorContextAnalyser` ships without a separate spec; its design fell out of a brainstorming session inline with the pzmm-pattern-port discussion. - New synthetic fixture `test/src/Games/ProjectZomboid/fixtures/debug-server-42x-minimal.txt` mirroring the existing B41 fixture in PZ B42 line shape. ### Changed - **`DebugServerPattern::LINE` regex relaxed** to handle PZ build 42.x. The Indie Stone dropped the per-line `t:` (microsecond) field and tightened the spacing between `f:N`, `t:N`, and `st:N,N,N,N>` markers somewhere on the way to build 42.17. The previous regex required the full `f:\d+,\s+t:\d+,\s+st:` triplet and silently failed on every B42 line. Now `(?:,\s+t:\d+)?` makes the `t:N,` field optional and `,?` makes the inter-field comma optional. Backwards-compatible — every B41 line continues to parse identically. `ProjectZomboidServerLogTest` now runs each parser-shape assertion via `#[DataProvider]` against both fixtures. - **Pass order in `ProjectZomboidRedactor::redact()`**: the new IP pass runs first, so the chain is now `IP → Steam ID → player name → coordinates`. The mandatory Steam ID → name → coordinates ordering is preserved; placement of the IP pass is by convention since its regexes are pattern-disjoint from the rest. - **`CLAUDE.md`** documents `iblogs` as the primary downstream consumer with a per-component checklist for cross-repo public API impact; the release-flow cadence; the feature-branch workflow set by the `redactor` and `iblogs-bootstrap` precedents; and the `docs/superpowers/specs|plans/` path convention. - **`.gitignore`** excludes `__pycache__/` (Python bytecode caches generated under `tools/pz-analyzer/`) and `*.bak` / `*.bak-*` (editor / manual backup files). ### Fixed - PZ build 42.x server logs now parse with proper level / prefix attribution. Previously, every B42 line failed `DebugServerPattern::LINE` and the resulting ServerLog entries fell through as level `INFO` with no prefix. This silently disabled `ServerExceptionProblem` and `ModMissingProblem` (their regexes anchor on `[timestamp]...` at entry start, which a level-less orphan entry doesn't emit). The anchorless `EngineVersionInformation` continued to fire against the joined entry text, producing the user-visible symptom "one Information badge, empty Problems panel" on B42 logs. The fix restores per-line parsing, re-enables both Problem classes, and makes the error-count badge populate correctly. ### Test counts - PHP suite: **287 tests, 654 assertions** (up from 260 / 492 at v0.2.0). - Python suite under `tools/pz-analyzer/`: **32 tests** (stdlib `unittest`, sub-10 ms). ## [0.2.0] — 2026-05-01 Render-time PII redaction utility added on the same calendar day as v0.1.0. Cut as a minor version bump rather than a patch because it adds a new public API surface (`RedactorInterface` plus the per-game implementation), which under semver is a minor change, not a patch. Consumers (notably iblogs) pin to `^0.2.0` to opt into the redactor-aware version. ### Added - `RedactorInterface` (`src/Util/RedactorInterface.php`) and `ProjectZomboidRedactor` (`src/Util/ProjectZomboid/ProjectZomboidRedactor.php`) — render-time PII filter that scrubs Steam IDs, player names, and world coordinates from Project Zomboid log content. Three independent toggles default to on. Designed as a string-in/string-out utility so consumers can apply it at any rendering or export step. Documented v1 limitations: in PvP combat lines, only the attacker's name and coords are redacted; victim's name and coords (after `hit`) are deferred to v2. In admin lines, `teleported X to ` coordinates are not redacted in v1. - 65 new test methods across six files under `test/tests/Util/Redactor/` — per-category unit tests, combined / toggle / idempotence matrix, and integration coverage that drives all 11 existing PZ fixtures through the redactor end-to-end. Suite total: 260 tests, 492 assertions. - `docs/superpowers/specs/2026-04-30-redactor-design.md` flipped from "deferred" to "implemented" status. Plan committed at `docs/superpowers/plans/2026-05-01-redactor.md`. ### Changed - New top-level `src/Util/` directory introduced. The Redactor is its first occupant; future utilities (e.g. tokenising redactor variants) land here. ## [0.1.0] — 2026-05-01 First public release. Codex is a generic PHP log parsing and analysis framework with full Project Zomboid server-log support across eight analysers. The Composer package name is `indifferentketchup/codex` (the repository directory and Gitea slug are `ik-codex`; the package name is not). ### Added - **Framework foundation** — generic `Log` / `Entry` / `Line` / `Parser` / `Analyser` / `Detective` / `Insight` pipeline forked from upstream `aternos/codex` and renamed end-to-end to `IndifferentKetchup\Codex\*` in `66a2fcc`. Zero `Aternos\Codex\*` namespace references remain in `src/` or `test/`. - **`FilenameDetector`** at `IndifferentKetchup\Codex\Detective\FilenameDetector` — path-based detector that uses the new `LogFileInterface::getPath()` accessor to dispatch on a filename hint. Falls back to `false` for path-less log files (`StringLogFile`, `StreamLogFile`). - **Project Zomboid log subclasses (11)** under `IndifferentKetchup\Codex\Log\ProjectZomboid\*` covering every PZ server-log file type: a multi-line `ProjectZomboidServerLog` for `DebugLog-server.txt`, an abstract `ProjectZomboidEventLog` base for the ten single-line logs, and concrete subclasses for `admin.txt`, `BurdJournals.txt`, `chat.txt`, `ClientActionLog.txt`, `cmd.txt`, `item.txt`, `map.txt`, `PerkLog.txt`, `pvp.txt`, `user.txt`. - **Pattern classes (11)** under `IndifferentKetchup\Codex\Pattern\ProjectZomboid\*` holding regex string constants. Each `Pattern` carries a `LINE` regex used by `PatternParser`, plus named-group extractor regexes (`FIELDS`, `COMBAT`, `MOD_LOAD`, etc.) used by analysers. - **`ProjectZomboidDetective`** at `IndifferentKetchup\Codex\Detective\ProjectZomboid\ProjectZomboidDetective` — pre-registers all 11 log subclasses in its constructor with paired filename-hint plus content-signature detectors. - **Phase B.1 ServerLog analysers (3)**: `EngineVersionAnalyser` (extracts engine version, build hash, and build date from the server banner), `ModLoadAnalyser` (mod load order plus missing-mod problems with attached `ModMissingSolution`), `ServerExceptionAnalyser` (Java exception type and stack-trace body, coalesced by exception type). - **Phase B.2 PvP and Admin analysers (2)**: `PvpDamageAnalyser` (filters zombie hits and zero-damage rows at the regex itself), `AdminAuditAnalyser` (verb-pattern dispatch across six admin actions: added item, added xp, granted access, changed option, reloaded options, teleported). - **Phase B.3 deferred analysers (3)** — first custom `Analyser` subclasses in the tree, addressing logic that vanilla `PatternAnalyser` cannot express: `ConnectionFailureAnalyser` (event pairing across the file), `ItemDuplicationAnalyser` (sliding-window heuristic with `THRESHOLD_COUNT=5`, `THRESHOLD_WINDOW_SECONDS=10`), `SkillProgressionAnomalyAnalyser` (consecutive-snapshot delta with `THRESHOLD_DELTA=3`). All three threshold constants ship with rationale docblocks and are tunable via subclass override. - **Synthetic test fixtures** under `test/src/Games/ProjectZomboid/fixtures/`, hand-crafted from observed PZ log shapes with placeholder identifiers per the project's privacy rules: Steam IDs `76561198000000001`–`76561198000000004`, names `Player1` / `Player2` / `AdminUser` / `PlayerSuspect`, generic coords. No real-log content reaches the index. - **End-to-end tests** validating each Log subclass's parser, each analyser's insight emission, and the Detective's dispatch behaviour against the synthetic fixtures. Final count: **195 tests, 412 assertions**. - **Project documentation**: `CLAUDE.md` with framework architecture, pitfalls, and workflow conventions; `README.md` with worked Project Zomboid example and per-game support table; design specs and as-built plans for Phase B.1 / B.2 / B.3 plus a deferred-status spec for the codex `Redactor` utility, all under `docs/superpowers/`. ### Changed - **Layout: components-outer with game suffix.** Every game's code lives at `IndifferentKetchup\Codex\\\*` for the existing components (`Analyser`, `Analysis`, `Detective`, `Log`, `Parser`, `Pattern`). This is option 1 from the Phase A Step 2 layout decision; option 3 (a flat `IndifferentKetchup\Codex\Games\\*` tree) was originally proposed and was **not** selected. - **`LICENSE`** retains the original `Copyright (c) 2019-2026 Aternos GmbH` line per MIT requirements; the LICENSE file is byte-for-byte unchanged from the upstream import. - **`composer.json`** rewritten in `aae016d`: package name `indifferentketchup/codex`, MIT license, generic-framework description, single author entry, PSR-4 autoload roots set to `IndifferentKetchup\Codex\` and the test-fixture / test-suite namespaces, PHP `>=8.4` require constraint, PHPUnit `^12` dev dependency. - **`tests.yaml`** uses the modern `$GITHUB_OUTPUT` workflow command instead of the deprecated `::set-output` (commit `60f12bc`). CI matrix runs PHP 8.4 and 8.5. - **`.gitignore`** excludes `Logs.zip` (real production log fixtures) and `.scratch/` (extracted reference logs), plus `.claude/` and `.claude.local.md` for personal Claude Code artefacts. ### Deferred - **Other game implementations** — `Minecraft`, `Hytale`, and `SevenDaysToDie` are detective-stub-only. Each has a TODO `Detective` extending base `Detective`; their per-component subdirectories under `Analyser`, `Log`, `Parser`, and `Pattern` contain only `.gitkeep` placeholders. Real implementations land if and when fixtures and demand exist. - **Packagist publication** — v0.1.0 is consumable via Composer's `vcs` repository entry pointing at the Gitea remote. Pushing to Packagist is a separate decision and is not in scope for this release. [0.3.0]: https://git.indifferentketchup.com/indifferentketchup/ik-codex/releases/tag/v0.3.0 [0.2.0]: https://git.indifferentketchup.com/indifferentketchup/ik-codex/releases/tag/v0.2.0 [0.1.0]: https://git.indifferentketchup.com/indifferentketchup/ik-codex/releases/tag/v0.1.0