D23 — Fundamentals-readiness hardening (triaged from the 2026-06-03 audit)
Architecture decision record, relocated verbatim from the retired single-file
docs/tenancy/decision log. Status, thematic clusters, and how to record a new ADR: the decision log index.
A 20-agent readiness audit (9 dimensions, adversarially verified + a completeness critic) found the
architecture mature but flagged enforcement/DX gaps. The findings were triaged with the user into
devops (deferred to a pipeline workstream), parallel features, and do-now hardening.
This entry records the do-now work; the rest is tracked under docs/tracking/.
Done now (all green — full suite + arch + PHPStan level 6 + Pint + scramble:export):
- Starter-kit settings removed. The Laravel starter-kit operator settings Livewire screens
(
Profile/Security/DeleteUserForm/Appearance/TwoFactor\RecoveryCodes) mutated Eloquent directly, bypassing the bus. Deleted them + their views, thesettings/*routes, the Livewire registrations, the global settings layout/partials, and their feature tests. Operator auth (login/2FA/passkeys/reset) and the dashboard are kept; the backoffice UI will be rebuilt afresh with every mutation dispatched through the CommandBus. (Logoutis kept — it touches only Auth/session, not Eloquent.) - Self-service registration disabled on the control plane (
Features::registration()removed, register view + binding + the sign-up link removed,RegistrationTestdeleted). Operators are provisioned, never self-signed-up. (Audit blocker.) - CQRS read/write architecture guards (
tests/Architecture/CqrsBoundaryTest.php): the rawDBfacade is confined to the bus + sanctioned internals, and the moduleHttp+Livewirepresentation layers may not import Eloquent models / the query builder /DB— so every domain read and write must flow through the bus. New presentation namespaces slot into the list (same per-module convention asModuleBoundaryTest). - PHPStan + Larastan added (
larastan/larastan ^3.0,phpstan.neon.distlevel 6, currently green;composer stan/make stan). 16 pre-existing type issues fixed in the process — including a real bug in the portedJsonApiEnvelopeExtension(getArg()never returns null, so a spuriousmessagefield leaked into list-envelope docs). No CI wiring (per instruction; the CI gap is tracked indocs/tracking/devops-hardening.md). - JSON:API collection contract (
Modules\Foundation\Http\Resources\JsonApiCollection, returned byJsonApiResource::collection()): list responses now carry the samemetablock as single resources plus JSON:API-shaped pagination (meta.pagecounts + top-levellinks), underapplication/vnd.api+json. Reference shape for every future index endpoint (test:tests/Feature/Foundation/JsonApiCollectionTest.php). - DX: tenant-aware test helpers (
Tests\TestCase::actingAsClient()+runInTenant());make stan/composer stan.
Tracked separately (see docs/tracking/): devops (CI PHPStan step, RLS deploy gate, prod
Horizon/scheduler, version parity), the durable audit trail (parallel feature), and the API
tooling/SPA-types/env-parity task. Deferred follow-ups: a CQRS module/command scaffolding
generator; the JSON:API collection Scramble extension + a filter/sort whitelist (land with the
first index endpoint); AuthenticateSession on auth routes; error tracking/observability.