kisenon
Agent-Safe Change Control

Sandboxes & promote

Pointez un agent de code IA vers votre base de données de production en toute sécurité — capturé, observé, promu par une porte, et réversible.

Fait partie de Agent-Safe Change Control. Les commandes keon sandbox et keon ledger ainsi que la vue Sandboxes de la console décrites ici sont en service — un keon récent est requis (cli-v0.1.46+).

Kisenon vous permet de confier à un agent de code (Claude Code, Cursor, le vôtre) une base de données qu'il peut modifier librement — sans risquer la production. Un sandbox est un fork par exécution de votre branche, avec une identification à portée limitée, un journal d'actions en direct, et une étape de promotion côté serveur. Cette page couvre la boucle complète : capture → travail → promote → atterrissage (réversible) → preuve.

Pourquoi c'est sûr

Deux garanties, toutes deux déterministes — aucun LLM ne siège dans le chemin de confiance :

  • L'agent ne peut pas toucher la production. Il se connecte avec une identification à portée limitée, non-superutilisateur, vers un fork. Il ne détient jamais d'identification capable d'écrire sur main. La promotion s'exécute côté serveur et n'applique que des changements qui ont déjà réussi dans le sandbox.
  • Vous voyez exactement ce qu'il a fait. Chaque instruction est attribuée et diffusée vers une console en lecture seule — le vrai SQL, pas un résumé.

La boucle

keon sandbox run \
  --migrate "alembic upgrade head" \
  --verify  "pytest tests/db"
# → green/red verdict + schema diff + a sandbox you can inspect

keon sandbox promote <id>   # cp applies the validated changes to main

L'agent garde le contrôle de la boucle ; c'est la borne qui la rend sûre.

Capture durable

Le journal d'actions est la source de vérité pour la promotion, il doit donc être complet. Chaque sandbox porte un capture_stateok ou lost. Si la capture est un jour compromise, l'état bascule vers lost et y reste : un sandbox perdu ne peut pas promouvoir (409 sandbox_capture_lost) et n'applique jamais silencieusement un changement partiel. Il n'y a pas d'auto-réparation — jetez-le et rejouez le travail dans un sandbox neuf. keon sandbox get / list montrent la santé de la capture.

Promote : en libre-service ou approuvé par un humain

Chaque projet choisit un promote_mode :

ModeQui valide sur main
self (défaut)L'agent promeut une fois ses vérifications passées — dans ses bornes.
humanL'agent propose ; un owner/admin examine le diff + le journal d'actions et clique sur Approve.

Essai à blanc du rayon d'explosion

Avant de promouvoir, vous pouvez demander à la plateforme de mesurer ce que la promotion ferait — niveaux de verrou réels, durées de maintien de verrou réelles, nombres de lignes réels — au lieu de deviner à partir du texte des instructions :

keon sandbox dry-run <id>

La plateforme rejoue le jeu d'instructions exact du sandbox contre deux forks jetables éphémères du parent — l'un au HEAD courant du parent (où les verrous, durées et lignes sont mesurés) et l'un au point de fork du sandbox (la ligne de base de divergence) — puis détruit les deux. Elle ne touche jamais main, et l'agent ne reçoit jamais d'identification vers l'un ou l'autre fork. L'essai à blanc est consultatif : il produit le rapport, il ne bloque jamais une promotion.

Il répond aussi à la question qu'un diff statique ne peut pas : la réalité a-t-elle bougé sous l'agent ? Toute instruction qui échoue, ou qui affecte un nombre de lignes différent, au HEAD du parent par rapport à ce qu'elle faisait au point de fork est signalée comme un conflit — p. ex. un UPDATE ... WHERE id = 2 dont la ligne cible a été supprimée sur main après le fork.

Le rapport achevé porte :

ChampSignification
statements[].lock_levelLe verrou le plus fort que l'instruction prend nouvellement dans la transaction de promotion (p. ex. AccessExclusiveLock pour une réécriture de table).
statements[].lock_wait_est_msTemps d'exécution mesuré sur le fork de tête — le plancher de la durée de maintien du verrou sur main.
statements[].rows_measuredLignes affectées sur le fork de tête (0 pour du DDL).
statements[].divergence{kind:"error"} ou {kind:"row_count"} quand l'instruction se comporte différemment au HEAD qu'au moment du fork.
rollup.conflictsChaque divergence, plus un marqueur baseline_unavailable si le couloir de ligne de base n'a pas pu s'exécuter — de sorte qu'une porte sur « aucun conflit » échoue fermée sur une mesure dégradée.
rollup.max_lock_level / rollup.duration_ms_totalForce de verrou agrégée et temps de rejeu total.
capture_advanced / parent_head_lsnSignaux de péremption : le rapport est un instantané, et le relancer est peu coûteux.

Les points de terminaison sont POST /v1/sandboxes/{id}/dry-run (démarre une exécution asynchrone, 202) et GET /v1/sandboxes/{id}/dry-run (le dernier enregistrement). Un essai à blanc échoué porte un error_code lisible par machine (capture_fence_failed, incomplete_capture, fork_failed, compute_unreachable, replay_infra_failed, timeout). Le panneau Blast radius sur la page de détail du sandbox affiche le même rapport dans la console.

Annuler une promotion

Une promotion est réversible. Avant que cp n'applique les instructions validées à main, il ancre l'état exact d'avant-promotion de la branche parente (un LSN). Une commande ramène la branche à cet ancrage :

keon sandbox undo <id>   # restore the parent branch to its pre-promote state

La chaîne de connexion du parent est inchangée — les clients se reconnectent au même point de terminaison. Undo est une action owner/admin ; les clés à capacité d'agent sont refusées (403 scope_insufficient), car une annulation écarte tout ce qui a atterri sur la branche après l'ancrage.

keon sandbox get <id> porte un objet undoundoable, restored_lsn, undone_at, et un blocked_reason quand il ne peut pas s'exécuter (superseded_by_later_promote, already_undone). Undo cible la promotion la plus récente uniquement, et rejette avec 409 (sandbox_not_promoted, undo_anchor_missing, undo_anchor_invalidated) une fois l'ancrage disparu. Il reste disponible tant que l'ancrage est valide et dans votre rétention de stockage — il n'y a pas de compte à rebours distinct.

Undo restaure par LSN : il annule tout ce qui suit l'ancrage, pas seulement le changement promu — y compris les écritures directes et les sessions d'agent ultérieures sur cette branche. Voir Common pitfalls.

Migrations émises

Chaque promotion atterrie émet une migration SQL up/down déterministe — aucun LLM, générée à partir du changement de schéma capturé et validée par aller-retour sur un fork jetable avant d'être proposée. Récupérez-la :

keon sandbox migration <id> --out ./migrations --wait

L'artefact porte le SQL up et down (files[], chacun avec un role), un drapeau coverage (full ou partial), down_fidelity, tout uncovered_seqs, un résultat validation, et un sha256. Les états terminaux sont validated, validation_failed, emission_failed, et no_schema_changes. v1 émet sql ; GET /v1/sandboxes/{id}/migration (et .../migration/files/{role}) le servent. L'émission s'exécute après l'atterrissage de la promotion et ne la bloque ni ne la retourne jamais — une promotion de données uniquement rapporte simplement no_schema_changes.

Registre signé

Chaque promotion et annulation ajoute un enregistrement signé et chaîné par hachage à un registre par projet — une attestation vérifiable hors ligne de ce qui a changé. La vérification ne nécessite aucun réseau et ne fait pas confiance à Kisenon :

keon ledger list --project <id>          # the chain (reports chain_ok)
keon ledger export <id> --out att.json   # one attestation document
keon ledger verify att.json              # offline; exit 0 iff valid
keon ledger keys --save                  # pin the signing keys you trust

keon ledger verify vérifie les signatures Ed25519 et la chaîne de hachage et rapporte les échecs précis (signature_invalid, statement_chain_mismatch, seq_gap, key_untrusted, chain_broken, …) ; la confiance est tri-état (trusted / untrusted / unverified). Routes : GET /v1/sandboxes/{id}/ledger, GET /v1/projects/{projectId}/ledger, GET /v1/ledger/keys.

Si cp n'a aucune clé de signature configurée, les promotions réussissent quand même mais sont non signées (ledger_enabled: false) — la signature n'est pas inconditionnelle.

Ce qu'un sandbox n'est pas

  • Pas un sandbox de code — il limite la portée de votre base de données, pas le processus de l'agent.
  • Pas un juge LLM — capture, rejeu et revue sont déterministes au niveau de l'octet.

Essayez-le

Essayez-le sur kisenon.com et voyez le quickstart.