ADR 044 · Accepted
Error-Analysis Tools with Fail-Closed Guards
Context
The agent can read content and configuration (ADR-042), but the debugging use cases admins actually bring to the playground — "why does this URL answer 500", "how do I fix this PHP error" — need capabilities the tool set lacked: reading the TYPO3 file logs with the failing source code, reading arbitrary project files, searching the code base, and probing a frontend URL. All four egress host-level data to an external LLM provider and take model-chosen (attacker-influenceable) arguments, so each needs a hard, fail-closed containment story.
Decision
Four admin-only tools, two shared guards.
Tools
- get_last_exception (group code)
Newest error-level entries from the TYPO3 file logs, with the parsed stack trace and ±6 lines of source context inlined for up to three project-local frames (vendor/core frames are listed, not expanded). index steps back through older errors, search filters.
- read_source (group code)
Line-ranged, line-numbered read of one project file (default 60, max 200 lines).
- search_code (group code)
Literal-substring (opt-in regex) search over project source files — a pure-PHP walk, no shell-out — returning path:line hits under a hard budget (20 000 files / 5 s), reported when exhausted.
- probe_url (group system)
One GET against the instance's own frontend: status, key headers, timing, a 2 KB tag-stripped body excerpt — and on a 5xx the newest error-log entries from the probe's ±30 s window are appended through the same log parser, so probe and cause arrive in one result.
Consequences
The "analyse the error" loop closes: probe_url → correlated log entry → get_last_exception (full trace + code) → read_source / search_code for the fix site — without leaving the playground.
All four tools are requiresAdmin() = true and live behind the ADR-043 group cascade (new group code; probe_url joins system), so one central toggle silences the whole family.
settings.php and other credential carriers are structurally unreadable even for admins — the guard has no bypass parameter by design.
probe_url performs real frontend requests (cache warm-up, log entries, load); it is deliberately GET-only, single-request, 15 s-capped.