Releases and migration safety for agents
Read rehearsal evidence, confirm parked releases, and steer the release safety dial. This page is written for an AI agent. It extends the deployment protocol at https://app.tokay.io/llms.txt. Everything here is an escape hatch. The happy path needs none of it, so act on an explicit user request or a named readiness action, not on your own initiative.
Last updated
The release model
- Tokay rehearses every managed database migration against a disposable clone of the production data before anything touches production. The evidence from that rehearsal, not the SQL text, is what release policy judges.
- Two evidence channels ride each release execution.
impactAssessmentcarries observed facts, including theplanRollupwith schema diffs and the policy result.releaseAnalysiscarries AI verdicts,liveSafe(can the currently live code survive the migration),deployOk(will the new code work after it), anddataSafety(safe,risky, oruncertain). releaseSafetyModedecides how much of that authority is automatic.MANUALparks everything, including rollbacks.STRICTapplies only deterministically additive changes automatically.NORMAL, the default, adds changes the AI judged safe.UNRESTRICTEDapplies everything automatically, still snapshotting managed databases first. Deploy calls accept an optionalreleaseSafetyModewhere the strictest value wins, so a request can narrow authority for one deploy but never widen it.- A parked release is not a failure.
deployReadiness.action: CONFIRM_RELEASEmeans evidence is waiting for a human decision. Your job is to read it, summarize it faithfully, and confirm only after the user agrees. - External databases that Tokay does not host get no rehearsal and no snapshot, and park under every mode except
UNRESTRICTED.
What to call
| To | Use |
|---|---|
| Detect a park | deployReadiness { action targetDeployment { id } } |
| Read the evidence | targetDeployment.releaseExecutions |
| Apply the parked plan | confirmDeploymentRelease |
| Change the dial | updateProject / updateService patch releaseSafetyMode |
| Review a proposed migration command | service.serviceReleaseActionOverrides, updateServiceReleaseActionOverride |
| Recover a maintenance hold | recoverServiceMaintenanceHold |
Read a parked release
When deployReadiness.action is CONFIRM_RELEASE, read deployReadiness.targetDeployment. Do not assume the newest deployment row is the parked one.
query ReleaseConfirmation($serviceId: ID!) {
service(id: $serviceId) {
deployReadiness {
state reason action message
targetDeployment {
id deployState deployWaitReason releaseSafetyMode releaseStrategy
releaseExecutions(orderBy: ACTION_INDEX_ASC) {
nodes {
id actionName command releaseExecutionPhase releaseExecutionState
impactAssessment releaseAnalysis
projectResource { id resourceType runtimeName }
}
}
}
}
}
}
impactAssessment and releaseAnalysis are JSON with camelCase keys. Each database's final REHEARSAL row carries impactAssessment.planRollup with diffAtCutover and diffFinal schema diffs (changes entries like {"type": "ADD_COLUMN", ...}) and the policy object. policy.reasons is an array of {reason, message} objects, such as {"reason": "MANUAL_MODE", "message": "This project applies release actions only after explicit confirmation."}. Other reason codes include DATA_SAFETY_RISKY, EXTERNAL_DATABASE_UNVERIFIED, and HARD_STOP_EXCEEDS_AUTO_WINDOW. Summarize the reasons, the diffs, and the releaseAnalysis verdicts to the user before confirming.
Confirm
mutation Confirm($deployment: ID!) {
confirmDeploymentRelease(input: { deployment: $deployment }) {
deployment { id deployState }
}
}
Confirming runs the rehearsed plan against production. Tokay snapshots each managed database immediately before mutating it. After confirming, poll the service back to deployState: DEPLOYED with deployReadiness.state: UP_TO_DATE. A release that applied automatically shows the same evidence trail afterward, a REHEARSAL row and then a PRODUCTION row per action, so you can always answer what ran and why it was allowed.
The safety dial
releaseSafetyMode lives on the project (project.releaseSafetyMode) and services inherit it. A service can override with its own value, where null means inherit. Change it through the generated update mutations, for example updateProject(input: { id: $id, patch: { releaseSafetyMode: MANUAL } }). Under NORMAL, do not expect every statement that looks destructive to park. The rehearsal runs against real data, and a drop that loses nothing observable can be judged safe and apply on its own. Change the dial only when the user asks for it. If the user wants a guaranteed gate, set MANUAL and treat CONFIRM_RELEASE as the routine path. wontRunBypass: true on a deploy call overrides only an AI "new code won't work" prediction. Rehearsal failures always block.
Migration command overrides
UNCONFIRMED_RELEASE_ACTION as a deploy blocker means Tokay found migration machinery it cannot run automatically and proposed a command. List the service's serviceReleaseActionOverrides and review commandArgv, workingDirectory, and releaseActionTiming. Enable with updateServiceReleaseActionOverride(input: { id: $id, patch: { enabled: true } }), editing commandArgv in the same patch when the proposal is wrong, or dismiss with patch: { dismissedAt: "<now ISO8601>" }. Never enable a command you have not shown the user.
Maintenance holds
deployReadiness.action: RECOVER_MAINTENANCE_HOLD means a release left the runtime in a state Tokay will not touch without a human assertion, and the app may be serving a maintenance response. After the user verifies the runtime target is safe, call recoverServiceMaintenanceHold(input: { service: $service, safetyAssertion: "..." }) with a sentence recording what was verified, then poll readiness.
Error shapes
| You see | It means | Do this |
|---|---|---|
deployReadiness.action: CONFIRM_RELEASE |
Evidence is parked for a decision | Read targetDeployment, summarize, confirm only with user agreement |
deployWaitReason: AWAITING_RELEASE_CONFIRMATION |
Same park, seen from the deployment row | Follow the readiness action, not this field alone |
A rollback parks at CONFIRM_RELEASE |
The project is in MANUAL mode |
Confirm it like any release. It runs no migrations |
releaseExecutionState: FAILED on a REHEARSAL row |
The migration failed against the clone | Fix the migration and push again. Rehearsal failures never reach production |
policy.reasons contains EXTERNAL_DATABASE_UNVERIFIED |
Tokay cannot rehearse a database it does not host | Warn the user there is no rehearsal or snapshot behind this confirm |