SIGNALS Documentation
API Reference

Rental Lifecycle Agent Guidance

Read-only preflight, legal command sequences, version and idempotency examples, and installed rental conflict recovery.

Rental lifecycle preflight

Run this read-only report inside the intended installation or selected Cloud tenant:

php artisan signals:rentals:lifecycle-preflight --json --no-interaction

The JSON lists the built-in composite codes, every stored rental-status definition (including inactive custom derivatives), and counts for every stored state/status pair. Composite codes are state * 100 + status; an invalid state or a status outside 0–99 is reported without borrowing a built-in meaning. Unknown codes, invalid derivatives and duplicate definitions make preflight_clear false.

project_tree_conflicts lists rental/project identifiers for connected trees with distinct direct projects, cycles, self-links or missing parents. Matching repeated assignments and a single child-only assignment are compatible with the current invariant. The audit includes archived rentals and all warehouses in the selected database. It does not repair rows, normalize assignments, fire events or change status definitions.

Cloud requires a bound database tenant; central and config-only contexts are refused before inspection. The output includes the tenant slug and application environment. Names, custom labels, account details, notes and connection credentials are omitted. Keep the resulting identifiers in the operator's internal incident or release record.

Exit status 0 means the selected data was available and no findings were detected. Exit status 1 means findings, unavailable reads or a refused tenant context. An unavailable read has null lists and a generic error, so an empty or partial report cannot be mistaken for a clean result.

Production findings

Production output has not been collected yet. The automated examples exercise fixtures in an isolated test database. They do not establish any production status vocabulary or conflict count. Production execution is a separate release-checklist item. Before release, a production operator must run the report in the intended tenant context and publish its actual code/derivative and conflict lists.

The command uses read-only queries and never applies a repair. Review findings with the rental source owner; resolve conflicting assignments through the admitted association/project commands after an operator decision.

Agent workflow: inspect, preflight, then command

Use whoami to establish the current identity, abilities and tenant. Read the rental with get-rental, then get-rental-available-actions (REST GET /api/v1/rentals/{rental}/available_actions). Retain aggregate_version; it is the command's expected_version, not the quote version number. Discover the exact operation with describe-endpoint before using execute-endpoint. Do not invent a curated tool for a command that is only exposed through the generic endpoint surface.

A positive preflight is not authorization. The command rechecks current permissions, state, warehouse access and evidence. For supported lifecycle transitions, first send dry_run: true to the same endpoint. Inspect allowed, reason and code; a dry run is not a reservation and does not commit the command. Submit once only after the operator approves the consequential change. After success, read the rental again before the next step.

For complete/cancel with descendants, use get-rental-cascade-preview first. Review the exact selected descendants and submit the root and selected-child version preconditions required by the described endpoint. Never interpret an empty selection as permission to cascade to every child.

Task Sequence and stop point
Create to quote to order Discover create-rental fields, create an enquiry, add permitted lines, read/preflight, then convert_to_quote; read/preflight again before convert_to_order. Resolve its real shortage/approval result rather than forcing state/status fields.
Revision acceptance Read the versions tree, create a revision or alternative with its intended source, review/diff the resulting version, send and accept only the customer's chosen version. Conversion uses the accepted version (active fallback if none); viewing a version does not activate it.
Safe line edit Read the current rental and line; submit only the intended quantity or field with the current aggregate version where admitted. For move, delete or restructure, also supply the exact required tree revision and active-version preconditions from the endpoint contract. Read committed totals afterward.
Dispatch and return An eligible order must use asset or loose-quantity fulfilment commands, with the actual assignment/quantity and evidence. Dispatch before return; never manufacture Dispatched, On Hire, Returned or Checked with change-rental-status.
Checkout Read/preflight the current source and review the selected invoice type and quantities. Generate the draft through the rental invoices endpoint, inspect its captured terms, then use the separate invoice issue workflow. An accepted-manifest refusal is not permission to replace captured terms with live prices.
Conflict recovery Read code, stop the old request, reconcile any uncertain effect, then re-read and ask before a destructive reapply. Never silently substitute current_version into the old payload.

Version and idempotency examples

The following are independent request shapes, not a script. IDs and versions are illustrative: replace them with the values just read in the selected tenant, and refresh after every successful command. Dry-run and commit requests are different intents. Use a fresh semantic key for each deliberate new operation and retain it with the exact payload for its retry.

The body idempotency_key is command metadata; replay exists only where that command installs a receipt. In particular, admitting this field on a lifecycle command does not promise deduplication. The HTTP Idempotency-Key header is a separate route-level contract: check x-signals-idempotency in the operation description. An absent extension promises no HTTP replay. Rental invoice generation has the route middleware; loose fulfilment also maps a supplied header to its body key and refuses mismatching keys. Do not send different header/body keys.

{
  "method": "POST",
  "path": "/api/v1/rentals/123/convert_to_quote",
  "body": {
    "dry_run": true,
    "expected_version": 7
  }
}
{
  "method": "POST",
  "path": "/api/v1/rentals/123/convert_to_quote",
  "body": {
    "expected_version": 7,
    "idempotency_key": "job-123-quote-decision-1"
  }
}
{
  "method": "POST",
  "path": "/api/v1/rentals/123/versions",
  "body": {
    "version_type": 0,
    "source_version_id": 456,
    "label": "Customer revision",
    "expected_version": 8,
    "idempotency_key": "job-123-revision-1"
  }
}
{
  "method": "POST",
  "path": "/api/v1/rentals/123/versions/457/accept",
  "body": {
    "expected_version": 9,
    "idempotency_key": "job-123-accept-457"
  }
}
{
  "method": "PATCH",
  "path": "/api/v1/rentals/123/items/789",
  "body": {
    "quantity": "2.00",
    "expected_version": 10,
    "idempotency_key": "job-123-line-789-quantity-1"
  }
}
{
  "method": "PATCH",
  "path": "/api/v1/rentals/123/items/789/fulfilment",
  "body": {
    "action": "dispatch",
    "quantity": "1.00",
    "expected_version": 11,
    "idempotency_key": "job-123-line-789-dispatch-1"
  }
}
{
  "method": "PATCH",
  "path": "/api/v1/rentals/123/items/789/fulfilment",
  "body": {
    "action": "return",
    "quantity": "1.00",
    "expected_version": 12,
    "idempotency_key": "job-123-line-789-return-1"
  }
}
{
  "method": "POST",
  "path": "/api/v1/rentals/123/invoices",
  "headers": {
    "Idempotency-Key": "job-123-standard-invoice-1"
  },
  "body": {
    "type": "standard",
    "expected_version": 13,
    "idempotency_key": "job-123-standard-invoice-1"
  }
}

For a known receipt-backed command, retry the same key and unchanged payload only after checking its recorded outcome. A timeout alone does not prove failure. Reconcile uncertain or expired results against recorded fulfilment or invoices before any new key. A new key is not a way to bypass an unresolved earlier command. If the operation has no installed replay contract, re-read its state/history instead of automatically resending it.

Conflict and refusal recovery

These are installed core codes, not a replacement for the current endpoint schema. Preserve the code and permitted diagnostic fields in the operator's incident record; do not disclose hidden tenants, accounts, costs or credentials. Custom/plugin refusals and an unrecognized code require source-owner review, not guessed recovery.

Code Recovery
version_conflict Re-read the rental and its current customer, lines and version; review the intended change, obtain approval for a destructive reapply, and send a fresh command. The change summary may be incomplete.
rental_repair_version_conflict Stop the stale repair. Reload the rental and aggregate version, rerun the supported repair inspection in report-only mode, and review the intended correction with the operator. A deliberate repair retry must supply the freshly reviewed expected version and reason, with all safety gates and current authorization still satisfied; never silently replace the version or bypass a hold.
rental_tree_version_conflict Reload the complete tree, its revision and active version. Rebuild the intended move/delete/restructure against that tree; do not reuse stale line IDs or a stale placement.
rental_version_constraint_conflict Reload the version tree and active version; check whether the intended revision/activation already happened before proposing another operation.
idempotency_conflict The key is bound to different intent (HTTP payload or editor command). Recover the original request/result; a genuinely different, approved operation needs its own key.
rental_item_delete_idempotency_conflict The delete key belongs to a different line. Reconcile that original deletion and use a distinct key only for a separately approved deletion.
rental_invoice_idempotency_conflict The checkout key's request or receipt contract differs. Inspect the original invoice/receipt; do not create another invoice to escape the conflict.
fulfilment_key_conflict Intent or authority differs from the recorded movement. Reconcile the original assignment/quantity and current authority before any new movement.
fulfilment_conflict A fulfilled rental cannot be reset to Active by ordinary status change. Use the supported fulfilment correction workflow and its actual evidence.
rental_owner_changed Reload the rental and component ownership/customer/state; re-establish access and review intent before resubmitting.
rental_lock_timeout, credit_lock_timeout Allow contention to clear, re-read the current resource and preflight before retrying. Do not assume a response timeout or surrounding workflow proves no earlier effect.
mutation_retry_exhausted The root mutation exhausted bounded database retries. Reload and review before a deliberate retry; do not spin an unbounded retry loop.
fulfilment_receipt_expired, fulfilment_outcome_unknown Reconcile recorded movements and source history; do not repeat the physical effect or rotate the key automatically.
idempotency_outcome_uncertain Stop replay and ask the operator to reconcile the recorded claim and effect before any new request.
idempotency_replay_authorization_changed Re-establish current access and reconcile the original outcome. Stored response access is refused; a new key requires a separate approved operation, not a blind retry.
rental_tree_revision_required Read the current tree token and supply the endpoint's explicit revision field/header. Do not invent a token or remove the precondition.
fulfilment_key_invalid, fulfilment_batch_selection_invalid Correct the blank/invalid key or actual bounded selection after reviewing the request; never change intent under a previously committed key.
fulfilment_boundary_required Integration code must start the keyed command at its own outer mutation boundary, with earlier queued intent committed or rolled back. Escalate to the integration owner.
invalid_state Read the current lifecycle and available actions; use a legal sequence rather than forcing a stored state/status.
shortage_block, fx_tax_locked, accepted_terms_locked Follow the specific shortage or pricing-evidence workflow with its permissions and operator decision. Do not weaken a lock, invent accepted evidence or substitute today's prices.
approval_required Inspect the existing approval handoff; do not keep calling conversion to force it through.

HTTP 425 means the same key is still in flight: wait briefly and inspect/retry the unchanged request under its advertised contract. HTTP 401/403/404 and ordinary field-validation failures are not concurrency retries; correct access or input through the supported workflow. Do not expose a hidden resource by switching tenants or dropping warehouse scope.

The installed command registrations, DTO rules, receipt handlers and refusal codes remain authoritative. This guidance does not claim generated-manifest coverage, mandatory versions for every legacy caller, universal semantic replay, production preflight collection, or adoption of pending status-repair/read-model changes.