仙kisenon
Agent-Safe Change Control

Bacs à sable et promotion

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_state — ok 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.

Dans un projet human, keon sandbox promote n'applique rien : le sandbox est mis en attente dans l'état awaiting_approval, et la réponse porte next_step: "approve" ainsi qu'un approve_hint indiquant la commande et qui peut l'exécuter. Le code de sortie empêche un script de prendre cette mise en attente pour un changement appliqué :

Code de sortieSignification
0Appliqué sur main.
1Échec — rien n'a été appliqué.
3En attente dans awaiting_approval — rien n'est encore appliqué. stderr porte une enveloppe sandbox_awaiting_approval ; un owner/admin doit exécuter keon sandbox approve <id>.

Un verdict (keon sandbox verdict <id> green|red) ne conditionne qu'une promotion ou une approbation à venir ; il n'est donc accepté que tant que le sandbox est active ou awaiting_approval. Dans tout autre état, il renvoie 409 sandbox_verdict_not_accepted.

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 undo — undoable, 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), coverage, down_fidelity, tout uncovered_seqs, un résultat validation, et un sha256. L'artefact est uniquement de schéma — il ne porte jamais d'écritures de données — et coverage indique la part de la promotion qu'il représente :

coverageSignification
fullChaque changement capturé figure dans l'artefact.
partialUne partie du DDL capturé n'est pas couverte par le diff de schéma ; elle est ajoutée telle quelle à la fin et listée dans uncovered_seqs.
schema_fullChaque changement de schéma est couvert, mais la promotion a aussi exécuté du DML (INSERT / UPDATE / DELETE) que l'artefact ne porte pas. data_omitted: true et omitted_data_seqs désignent ces écritures.

down_fidelity vaut full (down annule entièrement up), structural (down restaure la structure, pas les données — signalé à la place de full dès que des données ont été omises, ou quand up était destructif), partial (les instructions non couvertes n'ont pas de down généré), ou none. Pour annuler les écritures de données d'une promotion, utilisez keon sandbox undo, pas le script down.

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.

Bacs à sable et promotion · Kisenon