From b99d8f30610afd6b772706676e76d00668f90caa Mon Sep 17 00:00:00 2001 From: indifferentketchup Date: Fri, 1 May 2026 12:51:26 +0000 Subject: [PATCH] docs: backfill Phase B.2 spec and plan Retroactive design + plan documentation for Phase B.2 (PvP combat detection plus six admin verb-dispatch insight classes), reconstructed from chat history and git log. Mirrors the shape of the existing Phase B.1 docs. Plan is as-built with checkboxes pre-checked and commit SHAs referenced inline; Deviations section captures the 90c85a0 brace-fix interlude. --- .../2026-04-30-pz-analysers-pvp-admin.md | 116 ++++++++++++++++++ ...026-04-30-pz-analysers-pvp-admin-design.md | 106 ++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 docs/superpowers/plans/2026-04-30-pz-analysers-pvp-admin.md create mode 100644 docs/superpowers/specs/2026-04-30-pz-analysers-pvp-admin-design.md diff --git a/docs/superpowers/plans/2026-04-30-pz-analysers-pvp-admin.md b/docs/superpowers/plans/2026-04-30-pz-analysers-pvp-admin.md new file mode 100644 index 0000000..37b3e85 --- /dev/null +++ b/docs/superpowers/plans/2026-04-30-pz-analysers-pvp-admin.md @@ -0,0 +1,116 @@ +# ProjectZomboid Phase B.2 Analysers — As-Built Plan + +> Retroactive: written 2026-05-01. + +This document is a historical record of how Phase B.2 (PvP combat detection + admin verb dispatch) was implemented. The corresponding design spec is `docs/superpowers/specs/2026-04-30-pz-analysers-pvp-admin-design.md`. The work is complete and merged to `master`; checkboxes are pre-checked. + +**Goal:** Land seven new `Information` insight classes (one for PvP combat, six for admin verbs) under `src/Analysis/ProjectZomboid/`, plus seven new pattern constants on `PvpPattern` / `AdminPattern`, then wire `ProjectZomboidPvpLog` and `ProjectZomboidAdminLog` default analysers to register them. + +**Architecture:** Vanilla `PatternAnalyser` configured with the new insight classes. No custom `Analyser` subclasses (deferred to Phase B.3). `Entry::__toString()` joins lines with `\n`, but B.2 logs are single-line per entry so multi-line behaviour doesn't apply here. + +**Tech Stack:** PHP 8.4+, PHPUnit 12, Composer (root package: `indifferentketchup/codex`). PHP/Composer not installed on host — all command invocations wrap in `docker run --rm -v "$(pwd):/app" -w /app -u "$(id -u):$(id -g)" composer:latest …`. + +--- + +## Tasks + +### Task 0 — Pre-checkpoint + +- [x] Empty checkpoint commit: `df62da1 pre-phase-B.2 checkpoint` + +### Task 1 — `PvpDamageInformation` + `PvpPattern::COMBAT_REAL` + +- [x] Add `PvpPattern::COMBAT_REAL` constant (combat regex with negative lookahead on weapon and positive-non-zero damage clause) +- [x] Add `src/Analysis/ProjectZomboid/PvpDamageInformation.php` +- [x] Add `test/tests/Games/ProjectZomboid/Analysis/PvpDamageInformationTest.php` covering pattern shape, match extraction, and three rejection cases (zombie weapon, zero damage, negative damage) +- [x] `composer test` green: 167 tests, 343 assertions +- [x] Commit: `55f769c Add PvpDamageInformation insight` + +### Task 2 — `AdminAddedItemInformation` + `AdminPattern::ADDED_ITEM_ENTRY` + +- [x] Add `AdminPattern::ADDED_ITEM_ENTRY` constant (entry-anchored variant; the body-only `ADDED_ITEM` from Phase A stays in place) +- [x] Add `src/Analysis/ProjectZomboid/AdminAddedItemInformation.php` +- [x] Add `test/tests/Games/ProjectZomboid/Analysis/AdminAddedItemInformationTest.php` +- [x] Commit: `90c85a0 Add AdminAddedItemInformation insight` — **see Deviations section below** +- [x] Forward-fix: `0d85a05 Fix missing closing brace in AdminPattern` +- [x] `composer test` green after forward-fix: 170 tests + +### Task 3 — `AdminAddedXpInformation` + `ADDED_XP_ENTRY` + +- [x] Add `AdminPattern::ADDED_XP_ENTRY` constant +- [x] Add `src/Analysis/ProjectZomboid/AdminAddedXpInformation.php` +- [x] Unit test +- [x] `composer test` green: 173 tests +- [x] Commit: `a2faa55 Add AdminAddedXpInformation insight` + +### Task 4 — `AdminGrantedAccessInformation` + `GRANTED_ACCESS_ENTRY` + +- [x] Add `AdminPattern::GRANTED_ACCESS_ENTRY` constant +- [x] Add `src/Analysis/ProjectZomboid/AdminGrantedAccessInformation.php` +- [x] Unit test +- [x] `composer test` green: 175 tests +- [x] Commit: `caed04d Add AdminGrantedAccessInformation insight` + +### Task 5 — `AdminChangedOptionInformation` + `CHANGED_OPTION_ENTRY` + +- [x] Add `AdminPattern::CHANGED_OPTION_ENTRY` constant +- [x] Add `src/Analysis/ProjectZomboid/AdminChangedOptionInformation.php` +- [x] Unit test +- [x] `composer test` green: 177 tests +- [x] Commit: `b7b89ef Add AdminChangedOptionInformation insight` + +### Task 6 — `AdminReloadedOptionsInformation` + `RELOADED_OPTIONS_ENTRY` + +- [x] Add `AdminPattern::RELOADED_OPTIONS_ENTRY` constant +- [x] Add `src/Analysis/ProjectZomboid/AdminReloadedOptionsInformation.php` +- [x] Unit test +- [x] `composer test` green: 179 tests +- [x] Commit: `64641fa Add AdminReloadedOptionsInformation insight` + +### Task 7 — `AdminTeleportedInformation` + `TELEPORTED_ENTRY` + +- [x] Add `AdminPattern::TELEPORTED_ENTRY` constant (handles negative Z for basement coordinates) +- [x] Add `src/Analysis/ProjectZomboid/AdminTeleportedInformation.php` +- [x] Unit test (positive and negative Z cases) +- [x] `composer test` green: 182 tests +- [x] Commit: `d15fc81 Add AdminTeleportedInformation insight` + +### Task 8 — Wire `ProjectZomboidPvpLog::getDefaultAnalyser()` + +- [x] Replace `return new PatternAnalyser();` with `(new PatternAnalyser())->addPossibleInsightClass(PvpDamageInformation::class)` +- [x] Add `test/tests/Games/ProjectZomboid/Analyser/PvpLogAnalysisTest.php` — asserts three real-PvP insights (Bare Hands, Tire Iron, Hunting Knife) and zero zombie/vehicle insights +- [x] `composer test` green: 184 tests +- [x] Commit: `51eb2de Wire ProjectZomboidPvpLog default analyser` + +### Task 9 — Wire `ProjectZomboidAdminLog::getDefaultAnalyser()` + +- [x] Register all six `AdminInformation` classes +- [x] Add `test/tests/Games/ProjectZomboid/Analyser/AdminLogAnalysisTest.php` — asserts the 2+2+2+2+1+2 distribution and confirms the duplicate ShotgunShells row coalesces with `counter == 2` +- [x] `composer test` green: 186 tests +- [x] Commit: `c57d646 Wire ProjectZomboidAdminLog default analyser` + +--- + +## Deviations from the original plan + +### The `90c85a0` brace-fix interlude + +Task 2's commit (`90c85a0 Add AdminAddedItemInformation insight`) shipped broken. While adding the first `_ENTRY` constant to `AdminPattern.php`, the `Edit` tool's `old_string` was `\n}` and the `new_string` included a docblock plus the new constant but **dropped the closing brace** of the class body. The commit was made before the test result was inspected, so it landed with a `ParseError: Unclosed '{'` and 9 cascading test errors. + +Forward-fix `0d85a05 Fix missing closing brace in AdminPattern` restored the brace as a separate commit (per the `CLAUDE.md` workflow rule: "Always create new commits rather than amending"). The broken intermediate commit remains in history; force-pushing master to clean it would have cost more than the cosmetic gain. + +The remaining five admin commits (Tasks 3–7) used a deliberate practice change: every subsequent `Edit` to `AdminPattern.php` included the closing `}` in both `old_string` and `new_string` so it couldn't be dropped again. No further breakage. + +### Total commit count + +11 commits vs the 10 originally outlined in the spec's planning section. The extra commit is the brace-fix. + +### Test-count divergence note (now resolved) + +When Phase B.1's plan was written I projected a final count of 158 tests for B.1; the actual landed count was 161 (off by 3 — Task 5's contribution wasn't summed in the plan footer). For B.2 the planned and actual per-step counts match exactly. No projection error this phase. + +--- + +## Done condition (met) + +After Task 9, `composer test` reports **186 tests, 387 assertions, all green** under PHPUnit 12.5.6 / PHP 8.5.5 (verified via the `composer:latest` Docker image). All five originally-planned analysers from the Step D Phase B scope (B.1's three plus B.2's two) are now operational on their respective Log subclasses. diff --git a/docs/superpowers/specs/2026-04-30-pz-analysers-pvp-admin-design.md b/docs/superpowers/specs/2026-04-30-pz-analysers-pvp-admin-design.md new file mode 100644 index 0000000..deb689e --- /dev/null +++ b/docs/superpowers/specs/2026-04-30-pz-analysers-pvp-admin-design.md @@ -0,0 +1,106 @@ +# ProjectZomboid analyser design (Phase B.2) + +> Retroactive: written 2026-05-01. + +## Summary + +Add Project Zomboid PvP combat detection (filtering zombie hits and zero-damage events) and admin verb-dispatch coverage of six action types, by registering seven new `Information` insight classes onto the existing `PatternAnalyser`. No custom `Analyser` subclasses are introduced in this phase — all dispatch fits within `PatternAnalyser`'s per-entry pattern matching. + +This document covers Phase B.2. Phase B.1 is in `2026-04-30-pz-analysers-design.md`. Phase B.3 (cross-entry / threshold analysers requiring custom `Analyser` subclasses) is in `2026-04-30-pz-analysers-deferred-design.md`. + +## Scope + +- **In scope:** `PvpDamageInformation` + `PvpPattern::COMBAT_REAL` regex; six `AdminInformation` classes + six `AdminPattern::_ENTRY` regex constants; wiring `ProjectZomboidPvpLog::getDefaultAnalyser()` and `ProjectZomboidAdminLog::getDefaultAnalyser()`; end-to-end tests for both logs. +- **Out of scope (B.2):** any cross-entry / threshold / pairing logic (deferred to B.3); the eight other PZ logs whose `getDefaultAnalyser()` continues returning an empty `PatternAnalyser` stub; the codex-side `Redactor` utility (deferred — see `2026-04-30-redactor-design.md`). + +## Architectural decision: vanilla PatternAnalyser + +Phase B.1 established that `PatternAnalyser` plus `Insight::isEqual()` coalescing covers single-entry pattern matching cleanly. Phase B.2's analysers (PvP damage rows, admin verb lines) all fit that mould — each interesting line is independent of the others, dispatch is per-entry, and counter-coalescing handles repeats. No `Analyser` subclassing required. (Phase B.3 will deviate from this when cross-entry logic enters the picture.) + +## Components + +All under `src/Analysis/ProjectZomboid/`: + +| Class | Type | Pattern | Coalescing | +|---|---|---|---| +| `PvpDamageInformation` | Information | `PvpPattern::COMBAT_REAL` | Default `Information::isEqual` (label + value) — same attacker/victim/weapon coalesces | +| `AdminAddedItemInformation` | Information | `AdminPattern::ADDED_ITEM_ENTRY` | Default — same admin/item/target coalesces | +| `AdminAddedXpInformation` | Information | `AdminPattern::ADDED_XP_ENTRY` | Default — same admin/amount/skill/target coalesces | +| `AdminGrantedAccessInformation` | Information | `AdminPattern::GRANTED_ACCESS_ENTRY` | Default — same admin/level/target coalesces | +| `AdminChangedOptionInformation` | Information | `AdminPattern::CHANGED_OPTION_ENTRY` | Default — same admin/option/value coalesces | +| `AdminReloadedOptionsInformation` | Information | `AdminPattern::RELOADED_OPTIONS_ENTRY` | Default — same admin coalesces | +| `AdminTeleportedInformation` | Information | `AdminPattern::TELEPORTED_ENTRY` | Default — same admin/target/coords coalesces | + +## Patterns + +Seven new constants total. + +**`PvpPattern::COMBAT_REAL`** — combat regex with the noise filter baked in. The negative lookahead `(?!zombie")` rejects zombie weapon rows; the damage clause uses alternation to match only positive non-zero floats: + +``` +'/Combat: "(?[^"]+)" \([^)]+\) hit "(?[^"]+)" \([^)]+\) weapon="(?(?!zombie")[^"]+)" damage=(?0\.0*[1-9][0-9]*|[1-9][0-9]*\.[0-9]+)/' +``` + +The damage alternation explicitly rejects `0.000000` and any leading-minus value because both branches require either `0.` or `.`. + +**`AdminPattern::_ENTRY`** — six entry-anchored variants of the existing body-only verb constants. Necessary because `PatternAnalyser` calls `preg_match_all` against the full Entry text (including the `[time]` prefix), so the Phase A verb constants anchored at `^` would never match. The Phase A constants stay intact for direct-message use; new ones live alongside them on the same `AdminPattern` class. + +## Wiring + +Two `getDefaultAnalyser()` overrides (was `return new PatternAnalyser();` for both): + +```php +// ProjectZomboidPvpLog +return (new PatternAnalyser()) + ->addPossibleInsightClass(PvpDamageInformation::class); +``` + +```php +// ProjectZomboidAdminLog +return (new PatternAnalyser()) + ->addPossibleInsightClass(AdminAddedItemInformation::class) + ->addPossibleInsightClass(AdminAddedXpInformation::class) + ->addPossibleInsightClass(AdminGrantedAccessInformation::class) + ->addPossibleInsightClass(AdminChangedOptionInformation::class) + ->addPossibleInsightClass(AdminReloadedOptionsInformation::class) + ->addPossibleInsightClass(AdminTeleportedInformation::class); +``` + +## Test plan + +Unit tests under `test/tests/Games/ProjectZomboid/Analysis/`, one per Insight class — exercises `getPatterns()` shape, `setMatches()` extraction, and at least one filter-rejection case for `PvpDamageInformation` (zombie weapon and zero-damage rejection). + +End-to-end tests under `test/tests/Games/ProjectZomboid/Analyser/`: + +- `PvpLogAnalysisTest` against `pvp-minimal.txt`: asserts exactly three `PvpDamageInformation` insights (Bare Hands, Tire Iron (Worn), Hunting Knife). Zombie and vehicle rows must be filtered out by the regex. +- `AdminLogAnalysisTest` against `admin-minimal.txt`: asserts 2 + 2 + 2 + 2 + 1 + 2 = 11 insights across the six admin classes, with the duplicate ShotgunShells row coalescing into a single insight at `counter == 2`. + +## Fixture changes + +None. The Phase A synthetic fixtures `pvp-minimal.txt` and `admin-minimal.txt` already cover every code path Phase B.2 exercises. + +## Commits (as-built, in order) + +1. `df62da1` — `pre-phase-B.2 checkpoint` (`--allow-empty`) +2. `55f769c` — `Add PvpDamageInformation insight` +3. `90c85a0` — `Add AdminAddedItemInformation insight` ⚠️ broken — see `2026-04-30-pz-analysers-pvp-admin.md` §Deviations +4. `0d85a05` — `Fix missing closing brace in AdminPattern` (forward-fix for #3) +5. `a2faa55` — `Add AdminAddedXpInformation insight` +6. `caed04d` — `Add AdminGrantedAccessInformation insight` +7. `b7b89ef` — `Add AdminChangedOptionInformation insight` +8. `64641fa` — `Add AdminReloadedOptionsInformation insight` +9. `d15fc81` — `Add AdminTeleportedInformation insight` +10. `51eb2de` — `Wire ProjectZomboidPvpLog default analyser` +11. `c57d646` — `Wire ProjectZomboidAdminLog default analyser` + +11 commits total, vs 10 originally planned. The brace-fix commit accounts for the discrepancy. + +## Open issues + +None blocking. Phase A Q4 (admin verb scope) was settled before B.2 began. Phase B Q2 confirmed PvP fixtures contain real combat events worth analysing. + +## Pointers + +- Phase B.1 (foundation): `2026-04-30-pz-analysers-design.md` and `2026-04-30-pz-analysers.md`. +- Phase B.3 (deferred analysers requiring custom `Analyser` subclasses): `2026-04-30-pz-analysers-deferred-design.md`. +- Workflow conventions: `CLAUDE.md` § Workflow conventions and § Pitfalls.