The JsonReporter produces a canonical, schema-versioned JSON report. The
package needs a dedicated viewer — currently console + markdown are good for
single CI runs, but there's no way to browse historical runs, drill into failed
session chains visually, or compare environments. Open shape: standalone static
HTML+JS, PHP server, or CLI TUI — no commitment yet. (Memory:
project_future_json_viewer.md.)
Assertions can now opt into {KEY} resolution by implementing
Assertion\ResolvableAssertion (withResolver(VariableResolver): self).
CaseTranslator::resolveAssertions() rebuilds them right before evaluation, so
the runner sees fully-resolved args.
Status today:
RedirectAssertionimplements it —expectRedirect('{APP_BASE_URL}/login')works.- Most other assertions (
JsonPath,Contains,HeaderContains,HtmlElement, …) still own raw args. AddingResolvableAssertionto them is mechanical: take aVariableResolver, callresolve()on each string field, return a new instance. {@capture}substitution still doesn't reach assertions —CaptureStoreisn't threaded into the resolution path. Likely follow-up: a parallelCaptureAwareAssertioninterface, or fold both into onewithContext(VariableResolver, CaptureStore)method.
Workaround until everything is covered: expect(Closure) for dynamic checks
based on captured state.
bashbackground commands sometimes don't capturephpstdout to the output file. Use> /tmp/file.txt 2>&1redirection explicitly or run synchronously.vendor/bin/phpunitshim can drop output;php vendor/phpunit/phpunit/phpunitis more reliable.intelephenseshows false-positive "undefined type" for PSR/PHPUnit classes before/after vendor index — ignore unless PHPStan also complains.
- Don't add docblock summaries to silence linters or "for documentation". The user has been clear: code should explain itself, comments are a smell.
- Don't add
@phpstan-ignoreor baseline entries. PHPStan errors are real bugs. - Don't reintroduce
curl_close()— no-op since PHP 8.0, emits deprecation. - Don't auto-
git initor auto-commit. Wait for user instruction. - Don't wrap the
Containerretrieval pattern in extra abstractions;getTyped(Foo::class)is the contract.