feat(harness): per-run auto-approval of layer-2 proposals for model measurement
런 옵션 auto_approve_after_s(runs 열·POST /runs)를 추가한다. 값이 양수면 하네스가 제안 등록 뒤 그 지연만큼 기다렸다가 스스로 승인(actor auto)하고 HITL 버튼 경로와 같은 방식으로 조치를 실행(actor ai-approved, MarkProposalExecuted)한다. 사람 없이 모델 비교 캠페인을 반복하기 위한 측정 모드로, MTTA는 지연값으로 고정되고 판정 로직은 그대로다(2층 판정은 ai-approved 조치에서 나온다). 이미 결정·만료된 제안과 기록 전용 조치는 API 경로와 같이 처리한다.
This commit is contained in:
1 parent
f671e2419f
commit
ca933a646e
4 files changed
+82
-26
No files matched your search
+27
-21
@@ -24,27 +24,29 @@ type RunManager struct {
|
||||
}
|
||||
|
||||
type activeRun struct {
|
||||
RunID string
|
||||
Campaign string
|
||||
Model string // LLM for this run's diagnoses ("" = AI VM default); passed to the AI VM on every /diagnose
|
||||
ScenarioID string // "" between scenarios
|
||||
Scenario *Scenario
|
||||
TInject time.Time
|
||||
cancel context.CancelFunc
|
||||
RunID string
|
||||
Campaign string
|
||||
Model string // LLM for this run's diagnoses ("" = AI VM default); passed to the AI VM on every /diagnose
|
||||
AutoApproveAfter time.Duration // >0: measurement mode, the harness approves and executes layer-2 proposals after this delay
|
||||
ScenarioID string // "" between scenarios
|
||||
Scenario *Scenario
|
||||
TInject time.Time
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
type RunRequest struct {
|
||||
Campaign string `json:"campaign"`
|
||||
Model string `json:"model"` // optional: LLM id for the diagnoses (e.g. gpt-6-luna, claude-sonnet-5-5); "" = AI VM default
|
||||
ScenarioIDs []string `json:"scenario_ids"`
|
||||
BaselineS *int `json:"baseline_s"` // default 300 (design 8)
|
||||
CooldownS *int `json:"cooldown_s"` // default 300
|
||||
ObserveTimeoutS *int `json:"observe_timeout_s"` // default 1800
|
||||
MinObserveS *int `json:"min_observe_s"` // default 180: earliest t_recover (12 probe successes after inject)
|
||||
DriftBefore *int `json:"drift_before"`
|
||||
GitSHA string `json:"git_sha"`
|
||||
Notes string `json:"notes"`
|
||||
SkipRevert bool `json:"skip_revert"`
|
||||
Campaign string `json:"campaign"`
|
||||
Model string `json:"model"` // optional: LLM id for the diagnoses (e.g. gpt-6-luna, claude-sonnet-5-5); "" = AI VM default
|
||||
ScenarioIDs []string `json:"scenario_ids"`
|
||||
BaselineS *int `json:"baseline_s"` // default 300 (design 8)
|
||||
CooldownS *int `json:"cooldown_s"` // default 300
|
||||
ObserveTimeoutS *int `json:"observe_timeout_s"` // default 1800
|
||||
MinObserveS *int `json:"min_observe_s"` // default 180: earliest t_recover (12 probe successes after inject)
|
||||
DriftBefore *int `json:"drift_before"`
|
||||
GitSHA string `json:"git_sha"`
|
||||
Notes string `json:"notes"`
|
||||
SkipRevert bool `json:"skip_revert"`
|
||||
AutoApproveAfterS *int `json:"auto_approve_after_s"` // measurement mode (model comparison without a human in the loop): nil/0 = off
|
||||
}
|
||||
|
||||
// modelRe bounds the model id (empty = AI VM default). The AI VM routes by prefix: claude-* -> Anthropic, else OpenAI.
|
||||
@@ -98,9 +100,13 @@ func (a *App) handleRunCreate(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
runID := newID("run-")
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
m.active = &activeRun{RunID: runID, Campaign: req.Campaign, Model: req.Model, cancel: cancel}
|
||||
var autoAfter time.Duration
|
||||
if req.AutoApproveAfterS != nil && *req.AutoApproveAfterS > 0 {
|
||||
autoAfter = time.Duration(*req.AutoApproveAfterS) * time.Second
|
||||
}
|
||||
m.active = &activeRun{RunID: runID, Campaign: req.Campaign, Model: req.Model, AutoApproveAfter: autoAfter, cancel: cancel}
|
||||
m.mu.Unlock()
|
||||
if err := a.store.CreateRun(r.Context(), runID, req.Campaign, req.DriftBefore, req.GitSHA, req.Notes, req.Model); err != nil {
|
||||
if err := a.store.CreateRun(r.Context(), runID, req.Campaign, req.DriftBefore, req.GitSHA, req.Notes, req.Model, req.AutoApproveAfterS); err != nil {
|
||||
m.mu.Lock()
|
||||
m.active = nil
|
||||
m.mu.Unlock()
|
||||
@@ -110,7 +116,7 @@ func (a *App) handleRunCreate(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
mRuns.Set(1)
|
||||
go m.execute(ctx, runID, req)
|
||||
writeJSON(w, 202, map[string]any{"run_id": runID, "scenario_ids": req.ScenarioIDs, "model": req.Model})
|
||||
writeJSON(w, 202, map[string]any{"run_id": runID, "scenario_ids": req.ScenarioIDs, "model": req.Model, "auto_approve_after_s": req.AutoApproveAfterS})
|
||||
}
|
||||
|
||||
func (a *App) handleRunAbort(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in new issue
Block a user