kisenon
Agent-Safe Change Control

Häufige Fallstricke

Anti-Patterns, die Scale-to-Zero und Agentensicherheit still zunichtemachen — und wie man sie vermeidet.

Diese Muster werfen keinen Fehler. Sie bestehen CI, sie sehen in einem Diff vernünftig aus, und sie heben still eine Garantie auf, für die Sie bezahlen — Scale-to-Zero-Ersparnisse oder Agentensicherheit. Jedes unten: was passiert, warum es schmerzt und der Fix.

Keep-alive-Code macht Scale-to-Zero zunichte

Ein Agent fügt „hilfreich" Code hinzu, der die Datenbank auf einem Timer berührt. Jede periodische Abfrage zählt als Aktivität und setzt den Suspend-Timer zurück, sodass ein Endpunkt, den Sie so entworfen haben, dass er auf Null skaliert, niemals schläft — und Leerlauf aufhört, kostenlos zu sein.

Es kommt in mehreren Formen. Ein Frontend- oder Backend-Heartbeat:

// runs forever, holds the compute awake forever
setInterval(async () => {
  await pool.query("SELECT 1");   // "health check"
}, 30_000);

Ein externer Uptime-Monitor, der auf einen Endpunkt gerichtet ist, dessen Handler zufällig die DB abfragt — sodass jede Sonde den Compute weckt:

app.get("/health", async (_req, res) => {
  await pool.query("SELECT 1");   // monitored every 60s → never idle
  res.send("ok");
});

Oder Connection-Pool-Einstellungen, die eine lebende Verbindung mit Validierungs- Abfragen halten — ein min über Null oder ein serverloser „Warmer":

const pool = new Pool({
  min: 2,                         // keeps ≥2 connections open + validated
  // a validation/keep-alive query on each idle connection resets the timer
});

Fix: auditieren Sie agentengeschriebene Diffs auf periodischen Datenbankzugriff. Halten Sie Liveness- Prüfungen auf der HTTP-Schicht — sondieren Sie die App, nicht die DB — und lassen Sie den Pool auf Null leerlaufen (min: 0). Die Konsolen-Compute-Ansicht zeigt, warum ein Endpunkt nicht auf Null skaliert, was einen verirrten Heartbeat schnell aufzeigt.

Dem Agenten main-Anmeldeinformationen zu geben, umgeht ASCC

Einem Agenten den main-Branch-Connection-String zu geben — oder ihn keon angemeldet als Ihren eigenen Benutzer ausführen zu lassen — umgeht alles, was ASCC durchsetzt: Sandbox-Isolation, LEASH-Budgets, LINT- und BLAST-Prüfungen, Promote-Gates, Zuordnung und Undo-Anker. Der Agent schreibt nun die Produktion direkt, und keine der Schleife, die Agenten-Änderungen sicher macht, läuft jemals.

Der Agent sollte niemals eine Anmeldeinformation halten, die main schreiben kann. Die Promotion ist per Design serverseitig — cp ist der einzige Schreiber zur Produktion.

Fix: prägen Sie einen agentenbezogenen API-Schlüssel (capability = agent, scope = ein Projekt, kurzer Ablauf) unter Settings → API keys, übergeben Sie dem Agenten nur Sandbox- Connection-Strings und entfernen Sie stärkere Anmeldeinformationen aus seiner Umgebung (keine vollständige DATABASE_URL, keine ~/.pgpass, keine angemeldete keon-Sitzung in derselben Shell). Siehe Hand an agent a scoped credential und den SCOPE-Abschnitt von Guardrails.

Retry-Stürme rund um das Aufwachen

Die erste Verbindung nach einem Suspend muss den Compute wecken, also ist sie langsamer als eine warme. Ein Agent, der einen einzelnen langsamen Connect sieht, mag ihn „fixen" — mit aggressiven Client-Timeouts und Retry-Schleifen, die den Endpunkt hämmern, oder durch Hinzufügen eines Keep-alive (Fallstrick #1), sodass er nie aufwachen muss. Beide tauschen die Ersparnisse weg, um über eine einmalige Kosten hinwegzutäuschen.

Fix: setzen Sie einen Client-connect_timeout um 10 s und seien Sie beim ersten Connect geduldig. Der Kaltstart ist unter einer Sekunde in derselben Region, sobald warme Pfade im Spiel sind — ein leicht langsamer Connect ist zu erwarten, kein Fehler, um den herum man konstruiert.

postgresql://…?connect_timeout=10

In Code committete Anmeldeinformationen

Agenten hartcodieren Connection-Strings und API-Schlüssel in Quellcode und .env-Dateien, die dann git erreichen. Geleakte Schlüssel werden innerhalb von Stunden nach dem Erreichen eines öffentlichen (oder später öffentlichen) Repos abgeerntet — das Fenster wird in Stunden gemessen, nicht in Tagen.

Fix: injizieren Sie Geheimnisse über die Umgebung, committen Sie sie niemals. Halten Sie .env- Dateien aus git heraus. Bei jedem Leck rotieren Sie sofort über Settings → API keys — widerrufen Sie den exponierten Schlüssel und prägen Sie einen frischen.

Direktes DDL auf main umgeht die Promote-Schleife

Eine Migration direkt gegen main auszuführen, überspringt die Erfassung, die eine Änderung umkehrbar und auditierbar macht. Sie verlieren die emittierte up/down-Migration (EMIT), den signierten Ledger-Eintrag (LEDGER) und den Undo-Anker (UNDO). Das Schema änderte sich, aber es gibt keinen Datensatz, den die Plattform abspielen oder zurückrollen kann.

Fix: Sandbox → Promote, selbst für eine „triviale" Schemaänderung. Die Promote-Schleife ist es, die die Migration, den Ledger-Eintrag und den Anker erzeugt; ein direktes ALTER erzeugt keines davon.

Writes innerhalb einer zurückgerollten Transaktion landen trotzdem

Die Erfassung zeichnet die Anweisungen auf, die der Agent ausführt — sie hat kein Bewusstsein für Transaktionsgrenzen. Anweisungen, die innerhalb eines BEGIN … ROLLBACK ausgeführt werden, werden trotzdem erfasst, und wenn diese Sandbox promotet wird, werden sie abgespielt und angewendet. Ein ROLLBACK in der Sandbox hebt ihre Erfassung nicht auf.

BEGIN;
UPDATE users SET plan = 'pro';   -- captured
ROLLBACK;                        -- does NOT remove it from the capture

Fix: verlassen Sie sich nicht auf ROLLBACK innerhalb einer Sandbox, um explorative Arbeit „rückgängig zu machen". Wenn Sie Arbeit weg haben wollen, verwerfen Sie die Sandbox — das ist der Entsorgungspfad, den die Erfassung respektiert.

Arbeit in einer Sandbox über ihr Budget oder ihre TTL hinaus parken

Sandboxes sind ephemer. Wenn eine Sandbox ihr LEASH-Budget erschöpft, wird sie auto-verworfen (status=discarded), und jede nicht-promotete Arbeit darin ist verloren. Eine Sandbox als langlebigen Branch zu behandeln, zu dem Sie „zurückkommen werden", ist, wie die Änderungen eines Tages verschwinden.

Fix: promoten Sie sie oder erfassen Sie die Arbeit in einer frischen Sandbox erneut. Behandeln Sie Sandboxes standardmäßig als wegwerfbar — das dauerhafte Artefakt ist das Promote, nicht die Sandbox.

Die Garantien fehldeuten

Drei spezifische Fallen darin, was die Prüfungen tatsächlich versprechen:

  • Der Explosionsradius-Trockenlauf ist beratend. Er misst, was ein Promote tun würde — echte Locks, Dauern, Zeilenzahlen — aber er gatet das Promote niemals. Ein sauberer Trockenlauf ist Information, kein grünes Licht; und ob ein Trockenlauf vor dem Promote erforderlich ist, ist die Entscheidung von POLICY, nicht die des Trockenlaufs.

  • Approve kann ein Policy-Block nicht überschreiben. Ein menschliches Approve kann niemals ein Policy-block oder eine Anweisung außerhalb der Bahn durchwinken. Der einzige Weg an einem Block vorbei ist eine auditierte Policy-Änderung — es gibt keinen manuellen Override-Schalter, per Design.

  • Ein maskierter Fork maskiert Werte, nicht Form. Auf einem maskierten Fork sind die Werte maskiert, sodass datenabhängiges DML, das der Agent gegen diese maskierten Werte schreibt, beim Replay nicht die echten Zeilen auf dem Elternteil matchen wird. Schema-Bahn-Arbeit ist wertunabhängig und spielt treu ab; wertabhängiges DML, das gegen maskierte Daten entwickelt wurde, nicht.