Releases and migration safety for agents

This reference extends https://app.tokay.io/llms.txt with release and migration safety actions for AI agents. Use these actions only when the user explicitly asks or a named readiness action requires them.

Last updated

AI agent? Start with llms.txt.

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.
  • Each deploymentReleaseSession is one ordered resource plan. Its typed combinedImpactAssessment contains observed facts, releaseAnalysis contains AI verdicts, and policyResult.reasons explains any park. Internal rehearsal receipts remain flexible JSON; clients never parse them.
  • releaseSafetyMode decides how much of that authority is automatic. MANUAL parks everything, including rollbacks. STRICT applies only deterministically additive changes automatically. NORMAL, the default, adds changes the AI judged safe. UNRESTRICTED applies everything automatically, still snapshotting managed databases first. Deploy calls accept an optional releaseSafetyMode where 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_RELEASE means 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.releaseSessions
Apply the parked plan confirmDeploymentRelease
Change the dial setProjectReleaseSafety / setServiceReleaseSafety
Review a proposed migration command service.releaseActionOverrides, updateServiceReleaseActionOverride

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 {
      status reason action message
      targetDeployment {
        id state waitReason releaseSafetyMode releaseStrategy
        releaseSessions(first: 100, orderBy: CREATED_AT_ASC) {
          nodes {
            id isExternalTarget
            projectResource { id resourceType runtimeName }
            combinedImpactAssessment {
              preTrafficChanges { type operation requiresConfirmation database subject }
              finalChanges { type operation requiresConfirmation database subject }
              tableDeltas { database tableName inserts updates deletes }
              durationMs hasUnknownImpact
              unknownReasons { code database message }
              hasUnverifiedSideEffects
            }
            releaseAnalysis {
              currentCodeSafe currentCodeSafeReasons newCodeSafe newCodeSafeReasons
              dataSafety dataSafetyReasons startupMigrationWarning
            }
            policyResult {
              decision
              reasons { code message analysisReasons observedSeconds windowSeconds }
            }
            actions(first: 100, orderBy: ACTION_INDEX_ASC) {
              nodes {
                commandDisplay evidenceState
                releaseExecutions(first: 20, orderBy: CREATED_AT_ASC) {
                  nodes { type state exitCode logTail }
                }
              }
            }
          }
        }
      }
    }
  }
}

Summarize policyResult.reasons, destructive finalChanges, and the releaseAnalysis verdicts before confirming. preTrafficChanges is what the new code first sees. finalChanges is the completed plan. dataSafety is SAFE, RISKY, or UNCERTAIN. Reason codes include DATA_SAFETY_RISKY, EXTERNAL_DATABASE_UNVERIFIED, HARD_STOP_EXCEEDS_AUTO_WINDOW, MANUAL_MODE, REAPPLIES_UNDONE_CHANGE (the release changes data again right after a rollback restored it), and TOKAY_AUTHORED_DATA_CHANGE (it rewrites rows in a migration a Tokay fix proposal wrote).

Confirm

mutation Confirm($deployment: ID!) {
  confirmDeploymentRelease(input: { deployment: $deployment }) {
    deployment { id state }
  }
}

The first call changes nothing and fails with CONFIRMATION_REQUIRED, carrying the evidence summary and a token in extensions.confirmation. Repeat it with confirmationToken added to the input once the user agrees. Confirming runs the rehearsed plan against production. Tokay snapshots each managed database immediately before mutating it. After confirming, poll the service back to state: DEPLOYED with deployReadiness.status: 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. Direct API clients call setProjectReleaseSafety(input: { project: $id, releaseSafetyMode: MANUAL }) or setServiceReleaseSafety(input: { service: $id, releaseSafetyMode: null }). Loosening the effective mode requires PROJECT_DESTROY and confirms first: the first call fails with CONFIRMATION_REQUIRED and its impact, and the repeated call with confirmationToken applies it. Tightening needs only PROJECT_WRITE and applies at once. 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. bypassRunPrediction: true on a deploy call overrides only an AI "new code won't work" prediction. Rehearsal failures always block.

A release that drops or lossily changes schema, or deletes or rewrites existing rows, has policyResult.isDestructive: true, whether it parked or applied on its own. Once it runs, Tokay tells the user: the service's Activity gets a warning naming what changed, and whoever deployed it gets an email. Its restore point's expiresAt says how long it is kept, 7 days from the release.

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 releaseActionOverrides and review commandArgv, workingDirectory, and timing. Enable with updateServiceReleaseActionOverride(input: { id: $id, patch: { isEnabled: true } }), editing commandArgv in the same patch when the proposal is wrong, or dismiss it with dismissServiceReleaseActionOverride(input: { serviceReleaseActionOverride: $id }). Never enable a command you have not shown the user.

Maintenance holds

deployReadiness.action: ROLL_BACK means a hard-stop release changed the database and then failed, so the service serves its maintenance response. The version before the release may not run on the data as it is now. Roll back to deployReadiness.targetDeployment, which is still the current deployment, with rollbackService and restoreData: true to put the data back as it was before the release. Nothing was written to it while the service was down, though other services using the same database may have written. Or push a fix, which takes the hold over. See the operations reference for rollback.

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
waitReason: AWAITING_RELEASE_CONFIRMATION Same park, seen from the deployment row Follow the readiness action, not this field alone
state: FAILED on a REHEARSAL row The migration failed against the clone Fix the migration and push again. Rehearsal failures never reach production
policyResult.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