Skip to main content

Part 6 — Troubleshooting & Recap

Why this step exists: building the app is one thing; understanding what breaks and why is what makes you productive. This part collects the errors you are most likely to hit, how to debug them, and a recap of the whole system.

Common mistakes​

AUSUS exceptions are named precisely — the class name is the diagnosis. Here are the ones a beginner meets most often.

FieldRequired​

FieldRequired: helpdesk.ticket.title not in payload and no default

A create was invoked without a value for a non-nullable field that has no default. Fix: include every required field in inputs, or give the field a ->default(...) or ->nullable(). The React renderer's create modal validates required fields on the client and blocks submission before the server sees the request — see Create a ticket from the UI.

PolicyDenied​

PolicyDenied: helpdesk.ticket.start

The actor does not hold the role the action requires (ticket.agent). Fix on the CLI: pass the role in Application::create(['roles' => [...]]). Fix over HTTP: send the X-Actor-Roles header. Omitting it yields a roleless actor — every protected action returns 403 with the role the action actually requires (no demo fallback).

WorkflowStateMismatch​

WorkflowStateMismatch: current state 'OPEN' does not match any declared source

You invoked a transition that is not legal from the record's current state — for example resolve on an OPEN ticket. This is the workflow guard working. Fix the call order, or add the transition you intended.

BadRequest: missing required X-Tenant-ID header​

A projections/* or actions/* request arrived with no X-Tenant-ID. Fix: send -H 'X-Tenant-ID: helpdesk'. The React renderer sends it for you from the AususProvider tenant prop.

TenantBoundaryViolation​

The subject reference names a different tenant than the one the request runs in. Fix: the tenantId in a subject reference must match X-Tenant-ID (helpdesk throughout this tutorial).

AmbiguousWorkflowField​

AmbiguousWorkflowField: entity 'helpdesk.ticket' has multiple enum fields
with a default (priority, status)

The entity has two enum fields with defaults and no ->workflow() call, so AUSUS cannot guess which one is the lifecycle. Fix: declare the workflow explicitly — ->workflow(field: 'status', initial: 'OPEN') — which this tutorial does. (If you removed that line, this is the error you would see.)

ProjectionNotFound / ActionNotFound​

A 404 with one of these kinds means the FQN in the URL is wrong. FQNs are case-sensitive and fully qualified: it is helpdesk.ticket.summary, not ticket.summary or summary.

Class not found​

Error: Class "Helpdesk\TicketSystem" not found

Composer's autoloader has not indexed the class. Fix: confirm the file is src/TicketSystem.php, the namespace is Helpdesk, the PSR-4 rule is in composer.json, then run composer dump-autoload.

SQLite cannot open the database​

unable to open database file means the directory in the database path does not exist — SQLite creates files, not folders. Fix: use a path whose directory exists (this tutorial keeps tickets.sqlite in the project root).

Debugging tips​

A short checklist for when something is wrong:

  1. Read the exception class, not just the message. WorkflowStateMismatch, PolicyDenied, ConcurrencyConflict each point at a specific layer.
  2. Isolate with the CLI. If the browser misbehaves, reproduce it in a small PHP script with $app->invoke(...). That removes HTTP and React from the picture and tells you whether the bug is in the domain.
  3. Inspect the ViewSchema directly. Before blaming the renderer, run curl -H 'X-Tenant-ID: helpdesk' …/projections/helpdesk.ticket.summary and read the JSON. If the data is wrong there, the problem is server-side.
  4. Check the graph hash. GET /api/_health returns graphHash. If it does not change after you edit the plugin, the server is running stale code — restart php -S.
  5. Look in the database. sqlite3 tickets.sqlite 'SELECT * FROM helpdesk_ticket;' shows the real rows. SELECT action_fqn, timestamp FROM kernel_audit_log; shows every action that ran — the audit trail is your event history.
  6. Watch for deprecation notices. A line containing AUSUS deprecation: on boot() means you are relying on a legacy fallback (for example an implicit workflow). It still works, but fix it before it becomes an error.
  7. Read the server terminal. php -S prints PHP errors and stack traces in the terminal where it runs — keep that window visible.

Architecture recap​

You wrote one file of domain code — src/TicketSystem.php — and got a persisted, HTTP-exposed, browser-rendered application. Here is why that worked.

The layers​

TicketSystem plugin ← you wrote this
│ compiled by the Compiler
▼
MetadataGraph ← entities, fields, actions, workflows, projections
│ consumed by
▼
Runtime / Invoker ← preflight → policy → workflow guard → effect → audit
│ reads & writes
▼
SQLite persistence ← schema derived from the graph; + kernel_audit_log

And the outward-facing half:

HTTP Router (ausus/api-http) ← maps /projections + /actions onto the runtime
│ emits
▼
ViewSchema JSON ← fields + actions + data
│ consumed by
▼
@ausus/renderer-react ← draws lists, detail views, action dialogs

What happens on one action​

When you clicked Start in the browser, this is the full path:

  1. The renderer POSTed /api/actions/helpdesk.ticket.start with the ticket reference and the tenant/role headers.
  2. The Router parsed it and called the Invoker.
  3. The Invoker ran its chain inside one transaction: preflight (the action exists, the subject is in-tenant) → policy (the actor holds ticket.agent) → workflow guard (the ticket is OPEN, so OPEN → IN_PROGRESS is legal) → effect (write status = IN_PROGRESS) → audit (append to kernel_audit_log).
  4. The response went back as JSON; the renderer refetched the projection and redrew the row.

Every guarantee — tenancy, authorization, the legal-transition check, the audit entry — came from the metadata you declared, not from code you wrote per route.

What you built​

  • A domain plugin: 1 entity, 5 fields, 4 actions, 1 workflow, 2 projections.
  • A SQLite-backed application you ran on the CLI.
  • An HTTP API with health, projection and action routes.
  • A React UI that lists tickets and drives their lifecycle.

Remaining documentation gaps​

Honest notes on what this tutorial could not show, because the capability is not in v0.1.x:

  • Authentication. v0.1.0 has no auth layer; roles are passed as headers / config. A real deployment needs an auth middleware in front of the Router.
  • Databases other than SQLite. Persistence is validated on SQLite only.
  • List filtering and pagination. Projections return all rows for the tenant; pagination.nextCursor is always null.
  • Per-transition guard policies. Authorization is per action; a guard policy attached to an individual transition is designed but not run in v0.1.0.
  • Multiple entities and cross-entity references. This tutorial uses a single entity; relations between entities are not covered.

create-project installs the monorepo instead of the starter​

Symptoms​

After running:

composer create-project ausus/starter myapp

the generated directory contains unexpected folders such as:

  • packages/
  • apps/
  • docs-site/
  • renderer/
  • scripts/

and Composer output contains lines similar to:

Symlinking from packages/kernel

Cause​

Composer defaults to minimum-stability=stable. Without explicitly requesting the alpha channel, Composer resolves the latest stable 0.1.x release.

Resolution​

Use the documented alpha installation command:

composer create-project ausus/starter myapp

composer boot returns Command "boot" is not defined​

Cause​

This usually means the project was scaffolded from the legacy stable starter instead of the v0.2 alpha channel.

Resolution​

Delete the generated directory and reinstall using:

composer create-project ausus/starter myapp

Alpha resolution failure​

Symptom:

Your requirements could not be resolved to an installable set of packages.

Problem 1
- Root composer.json requires ausus/standard-stack ^0.2@alpha
- ausus/standard-stack v0.2.0-alpha.X requires ausus/api-http ^0.2@alpha
→ does not match your minimum-stability.

Cause. Your root composer.json has minimum-stability: stable (Composer default). When ausus/standard-stack@^0.2@alpha declares a transitive ausus/api-http ^0.2@alpha, that inner alpha constraint is evaluated against YOUR root's minimum-stability. Stable rejects it.

The @alpha flag on a single root require does not propagate to transitive dependencies — this is documented Composer behaviour, not AUSUS-specific.

Fix. Declare alpha stability at the root of your composer.json:

{
"minimum-stability": "alpha",
"prefer-stable": true
}

Or via CLI:

composer config minimum-stability alpha
composer config prefer-stable true
composer update

If you are using composer create-project, request the alpha channel explicitly:

composer create-project ausus/starter myapp

The flag is required for every v0.2.x alpha install until the first stable AUSUS release.

See Alpha installation requirements for the full explanation.

Packagist propagation delay​

Symptom. A new ausus/* version was just tagged on GitHub but composer require ausus/standard-stack:^0.2@alpha still pulls the previous version.

Cause. GitHub → Packagist webhook propagation typically takes 1–3 minutes (occasionally up to 15 min on slow days). Composer's local cache may also serve a stale package list.

Fix.

composer clear-cache
composer require ausus/standard-stack:^0.2@alpha --no-cache

If after 15 min the new version still doesn't appear, click the manual Update button on the package's Packagist page (https://packagist.org/packages/ausus/<name>).

npm dist-tag confusion​

Symptom. npm install @ausus/renderer-react returns a version that doesn't match what's documented as the current alpha.

Cause. npm dist-tags. AUSUS publishes pre-releases to @next and also promotes @latest to the current pre-release as long as no stable v1+ exists.

Fix. Be explicit:

# Default (gets @latest = current alpha until a stable v1+ exists)
npm install @ausus/renderer-react

# Always-current pre-release stream
npm install @ausus/renderer-react@next

# Specific version
npm install @ausus/renderer-react@0.2.0-alpha.4

See The React renderer — npm dist-tag policy.

Where to go next​

  • Core Concepts — the model behind everything you just used.
  • The PHP DSL — every builder method.
  • Workflows — transitions, guards, and the explicit workflow API in depth.
  • The HTTP API — the full route and error reference.

You have built a complete AUSUS application from zero. Everything larger is the same four moves: describe the domain, boot the Application, expose it, render it.