Pilot-to-production graduation¶
Bernstein sessions can operate at four increasingly trusted stages — sandbox, shadow, assisted, autonomous — and a session graduates from one to the next only after it clears a metrics threshold (task count, success rate, consecutive-failure ceiling, minimum time-at-stage). Graduation is exposed as a REST surface; there is no bernstein graduation CLI command.
Stage semantics¶
| Stage | What runs |
|---|---|
sandbox | Agents spawn but make no real changes (dry_run=True). |
shadow | Agents run and produce diffs; changes apply locally but are not committed. |
assisted | Changes are committed; each task merge requires explicit human approval. |
autonomous | Changes are committed and auto-merged after batch review. |
stage_to_orchestrator_overrides(stage) maps each stage to the OrchestratorConfig fields that enforce it (dry_run, approval, merge_strategy), so a stage is not just a label — it changes what the orchestrator is allowed to do.
Endpoints¶
| Endpoint | Does |
|---|---|
GET /graduation/status | All tracked sessions, current stage, and whether each can graduate. |
GET /graduation/config/policies | The active per-stage thresholds. |
GET /graduation/{session_id} | Stage, accumulated metrics, promotion log, and graduation readiness for one session. |
POST /graduation/{session_id}/record-event | Record a task success/failure against the session's current-stage metrics. Body required: task_id (string) and success (bool) are mandatory; duration_s, cost_usd, and initial_stage default to 0.0, 0.0, and "sandbox". |
POST /graduation/{session_id}/promote | Manually promote a session to the next stage. Returns 409 if already autonomous. Send a body ({} is enough); reason and promoted_by default to "manual" and "operator". |
Both POST endpoints validate their body, so calling them with no body — or with success but no task_id — returns 422, not 400. A session record is created on the first record-event; GET /graduation/{session_id} before that returns 404.
# record three successful tasks, then promote out of sandbox
curl -X POST "$BASE/graduation/$SESSION/record-event" \
-H "Content-Type: application/json" -d '{"task_id":"t1","success":true}'
curl -X POST "$BASE/graduation/$SESSION/promote" \
-H "Content-Type: application/json" -d '{}'
Default policies¶
| Stage | Min tasks | Min success rate | Max consecutive failures |
|---|---|---|---|
sandbox | 3 | 80% | 3 |
shadow | 5 | 85% | 2 |
assisted | 10 | 90% | 2 |
autonomous is terminal — it has no outbound policy, and promote on an already-autonomous session returns 409.
can_graduate also enforces min_hours (minimum wall-clock time at the current stage) where configured; the default policies above set it to 0 (no time requirement).
How promotion happens¶
A caller records each task outcome via record-event (success, duration_s, cost_usd). The graduation store accumulates per-stage metrics (tasks_completed, tasks_failed, consecutive_failures, success_rate, hours_elapsed) and evaluates them against the stage's policy on every read of GET /graduation/{session_id} or /graduation/status. Promotion itself is never automatic — a call to POST /graduation/{session_id}/promote is required even once can_graduate reports true. Every promotion appends an entry (from-stage, to-stage, timestamp, reason, promoted-by, metrics snapshot) to the session's promotion log.
Persistence¶
.sdd/graduation/<session_id>.json— current stage and per-stage metrics for one session..sdd/metrics/graduation.jsonl— append-only event log (task_eventandpromotionentries).
Limitations¶
- No CLI wraps these endpoints; an operator (or an external dashboard) drives graduation via the REST API directly.
- Nothing in the orchestrator calls
record-eventautomatically — a caller (dashboard, CI job, or operator script) is responsible for reporting task outcomes into the graduation store. Without that wiring, a session's graduation state never advances on its own.
Source¶
src/bernstein/core/quality/graduation.py— stages, policies,GraduationEvaluator,GraduationStore.src/bernstein/core/routes/graduation.py— the FastAPI routes listed above.