# AI Employees: persisted manual lifecycle rehearsal

24 September 2026. This extends the [draft-only runtime review](ai-employees-isolated-runtime.md). It tests actual application controls with a manually driven worker API, **not an autonomous employee, model or provider integration**.

## Isolation

Only the controlled review organization and handle `tutorial-lifecycle-20260924` are allowed through the temporary runtime's real status, enqueue, lease and sign-in issuance methods. The original `tutorial-coordinator-20260924` draft remains outside this exception. Six guard tests pass; [test evidence](assets/ai-employees/manual-lifecycle-isolation/guard-tests.txt).

The lifecycle fixture uses runtime provider `external`, with no provisioning and no runtime process. AI event handlers, heartbeat registration, bootstrap reconciliation, Bull consumers and stub execution remain disabled. Owner actions use the actual owner's session; worker calls use this employee's own password and authenticator sign-in. Credentials are stored privately and excluded from evidence.

This temporary full API clone also ran the unrelated service-pricing initializer at startup: its log reported four stale pricing records removed and fifteen skipped. This is disclosed rather than treating the process as completely free of non-AI bootstrap effects. A review-only suppression for that initializer has been prepared for future starts; no extra restart was made solely for it. Main API3312 and existing autonomous AI workers were not restarted.

## Observed controls

1. Real create returned a draft with its locked AI identity.
2. Switch on without access returned **400**.
3. The owner assigned the existing **Reviewer** group through the real access endpoint.
4. The real sign-in issuance endpoint generated this new employee's credentials and enrolled its authenticator locally. No provider received them.
5. Sign-in while draft returned **403**.
6. Owner switch-on succeeded; the employee completed password/authenticator sign-in and retrieved its own briefing.
7. A lease with daily budget zero returned no job and the budget-exhausted reason.
8. With a temporary budget of $1, attempting another employee's lease returned **403**.
9. The owner assigned a fictional checklist review. The employee leased it, reported an explicitly manual step, and requested approval before recording a training result.
10. The employee's attempt to approve its own request returned **403**.

The $1 budget is a control setting, not a charge or recorded model cost. No external contact, real operational task, payment or model call is part of this rehearsal.

11. In Studio, the owner opened **Approvals**, opened the request drawer and selected **Approve**. The job returned to in progress with the owner decision recorded, and the approval inbox became empty.
12. The employee leased the approved job again and completed it with zero reported cost. A different worker identifier could not report a step (**409**); duplicate completion also returned **409**.
13. A separate fictional retry rehearsal returned to the queue after its first reported failure, then reached **failed** after the second attempt, matching its maximum-attempts setting.
14. With working hours set to an empty midnight-to-midnight interval, lease returned no job and the outside-working-hours reason. Always-on hours were restored and daily budget returned to zero.

15. The owner selected **Pause** in Studio. The paused employee's existing token returned **403** from its briefing endpoint, and a fresh password sign-in returned **403** as well. A recent-contact **Online** badge did not override the paused/locked state.
16. A separate fictional request exercised the owner's **Reject** action. The job returned to in progress with a rejected decision; the employee resumed it and recorded that no action was performed. Rejection does not itself cancel the job.
17. The owner cancelled a separate unstarted training job. It became **cancelled**, and an attempted worker completion returned **409**.

The initial completed/retry/pause transcript is saved in [manual lifecycle proof](assets/ai-employees/manual-lifecycle-proof.json). The rejection and cancellation job IDs are `6ab5a1e47393e89fda21a4d9` and `6ab5a1e47393e89fda21a4da`. Actual owner UI captures:

![Owner approval request](assets/ai-employees-local/manual-approval-job-details.png)

![Completed manual job](assets/ai-employees-local/manual-completed-job.png)

![Failed after the retry ceiling](assets/ai-employees-local/manual-failed-job.png)

After the manual rehearsal, the same dedicated fixture was temporarily reactivated for a separately authorized genuine model trial with an inline fictional checklist. That trial is distinct from the manual evidence above; its result and final stop/pause are recorded separately.

## Reproducible control sequence

This is a developer acceptance sequence, not instructions to pretend that manual requests are autonomous AI work. Use the owner session for administrative routes and the actual employee session for worker routes. Every request carries the correct `orgid` header.

| Caller | Method and route | Relevant body |
|---|---|---|
| Owner | `POST /ai-employees` | Unique name/title, `runtime: {provider: "external"}`, `listensTo: []`, `workingHours: {alwaysOn: true, timezone: "UTC"}`, `limits: {dailyBudgetUsd: 0, maxConcurrentJobs: 1, maxAttempts: 2}` |
| Owner | `PUT /ai-employees/:name/access` | `{groups: ["Reviewer"]}`; use an existing appropriate group |
| Owner | `POST /ai-employees/:name/handover/sign-in` | `{}`; returned credentials remain private |
| Owner | `POST /ai-employees/:name/switch-on` | `{}` |
| Employee | `POST /profile/user/signin` | Own email and generated password |
| Employee | `POST /profile/security/challenge/verify` | Returned challenge token and own authenticator code |
| Owner | `PUT /ai-employees/:name` | `limits: {dailyBudgetUsd: 1, maxConcurrentJobs: 1, maxAttempts: 2}` for the controlled lease rehearsal |
| Owner | `POST /ai-employees/:name/work` | Fictional title/instructions, no external operation |
| Employee | `POST /ai-employees/worker/:name/lease` | `{worker: "manual-review"}` |
| Employee | `POST /ai-employees/worker/work/:id/step` | Same worker identifier and truthful manual step text |
| Employee | `POST /ai-employees/worker/work/:id/approval` | Same worker, `action: "other"`, summary of fictional training result |
| Owner | `POST /ai-employees/work/:id/decide` | `{decision: "approved"}`; exercised through Studio |
| Employee | Lease again, then `POST /ai-employees/worker/work/:id/complete` | Same worker, truthful manual result and `costUsd: 0` |
| Employee | For the separate failure rehearsal, `POST /ai-employees/worker/work/:id/fail` | Same worker, clearly intentional error and `retry: true`; lease again between attempts |

The original application methods persist these transitions. The disabled scheduler, event handlers and runtime execution remain review test controls, so this does not prove scheduled work or provider execution.

## Finance resource recheck

The local finance check still found no organization PayPal configuration. The shared PayPal provider remains sandbox-enabled with a client ID but no application secret, and no controlled recipient is known. No provider request was made. Existing ACH training batch remains untouched; zero new eligible ACH requests were found. [Organization readiness](assets/finance-local/paypal-local-readiness.json), [shared readiness](assets/finance-local/paypal-shared-readiness.json).
