Thread per-commitment enforcement level through to the snapshot
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -148,6 +148,7 @@ type Controller struct {
|
|||||||
reflectionGen int
|
reflectionGen int
|
||||||
|
|
||||||
allowedClasses []string // durable: the active session's allowed window classes
|
allowedClasses []string // durable: the active session's allowed window classes
|
||||||
|
enforcementLevel domain.EnforcementLevel // durable: block enables window-minimize enforcement
|
||||||
judge ai.DriftJudge
|
judge ai.DriftJudge
|
||||||
driftStatus string
|
driftStatus string
|
||||||
driftReason string
|
driftReason string
|
||||||
@@ -286,6 +287,7 @@ func New(snapshotPath string) (*Controller, error) {
|
|||||||
_ = store.PruneOlderThan(c.sessionsDir, sessionRetention, c.clock())
|
_ = store.PruneOlderThan(c.sessionsDir, sessionRetention, c.clock())
|
||||||
if c.runtimeState == domain.RuntimeActive && s.SessionID != "" {
|
if c.runtimeState == domain.RuntimeActive && s.SessionID != "" {
|
||||||
c.allowedClasses = s.AllowedWindowClasses
|
c.allowedClasses = s.AllowedWindowClasses
|
||||||
|
c.enforcementLevel = s.EnforcementLevel
|
||||||
// Drift state is not persisted: recompute fresh after restart to avoid
|
// Drift state is not persisted: recompute fresh after restart to avoid
|
||||||
// stale interrupts. This also initializes judgedClasses (the pipeline
|
// stale interrupts. This also initializes judgedClasses (the pipeline
|
||||||
// writes to it) so a restored Active session never panics on a nil map.
|
// writes to it) so a restored Active session never panics on a nil map.
|
||||||
@@ -432,6 +434,7 @@ func (c *Controller) persistLocked() error {
|
|||||||
snap.SessionID = c.stats.SessionID
|
snap.SessionID = c.stats.SessionID
|
||||||
}
|
}
|
||||||
snap.AllowedWindowClasses = c.allowedClasses
|
snap.AllowedWindowClasses = c.allowedClasses
|
||||||
|
snap.EnforcementLevel = c.enforcementLevel
|
||||||
snap.ReflectionStatus = c.reflectionStatus
|
snap.ReflectionStatus = c.reflectionStatus
|
||||||
snap.ReflectionRecap = c.reflectionRecap
|
snap.ReflectionRecap = c.reflectionRecap
|
||||||
snap.CarryForward = c.carryForward
|
snap.CarryForward = c.carryForward
|
||||||
@@ -701,6 +704,14 @@ func (c *Controller) AllowedClassesForTest() []string {
|
|||||||
return append([]string(nil), c.allowedClasses...)
|
return append([]string(nil), c.allowedClasses...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnforcementLevelForTest exposes the active session's enforcement level. Tests
|
||||||
|
// only.
|
||||||
|
func (c *Controller) EnforcementLevelForTest() domain.EnforcementLevel {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
return c.enforcementLevel
|
||||||
|
}
|
||||||
|
|
||||||
// SetDriftJudge injects the AI drift judge. A nil judge keeps local matching
|
// SetDriftJudge injects the AI drift judge. A nil judge keeps local matching
|
||||||
// working; unmatched windows simply stay idle.
|
// working; unmatched windows simply stay idle.
|
||||||
func (c *Controller) SetDriftJudge(j ai.DriftJudge) {
|
func (c *Controller) SetDriftJudge(j ai.DriftJudge) {
|
||||||
@@ -867,7 +878,7 @@ func coachErrorMessage(err error) string {
|
|||||||
// StartManualCommitment validates input, activates a new commitment, mints a
|
// StartManualCommitment validates input, activates a new commitment, mints a
|
||||||
// session, seeds evidence stats from the latest window, and moves Planning ->
|
// session, seeds evidence stats from the latest window, and moves Planning ->
|
||||||
// Active.
|
// Active.
|
||||||
func (c *Controller) StartManualCommitment(nextAction, successCondition string, timebox time.Duration, allowedClasses []string) error {
|
func (c *Controller) StartManualCommitment(nextAction, successCondition string, timebox time.Duration, allowedClasses []string, level domain.EnforcementLevel) error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
commitment, err := domain.NewManual(nextAction, successCondition, timebox)
|
commitment, err := domain.NewManual(nextAction, successCondition, timebox)
|
||||||
@@ -889,6 +900,7 @@ func (c *Controller) StartManualCommitment(nextAction, successCondition string,
|
|||||||
c.outcomePending = ""
|
c.outcomePending = ""
|
||||||
c.resetCoachLocked()
|
c.resetCoachLocked()
|
||||||
c.allowedClasses = append([]string(nil), allowedClasses...)
|
c.allowedClasses = append([]string(nil), allowedClasses...)
|
||||||
|
c.enforcementLevel = level
|
||||||
c.resetDriftLocked()
|
c.resetDriftLocked()
|
||||||
|
|
||||||
sessionID := "session-" + uuid.Must(uuid.NewV7()).String()
|
sessionID := "session-" + uuid.Must(uuid.NewV7()).String()
|
||||||
@@ -956,6 +968,7 @@ func (c *Controller) End() error {
|
|||||||
c.stats = nil
|
c.stats = nil
|
||||||
c.outcomePending = ""
|
c.outcomePending = ""
|
||||||
c.allowedClasses = nil
|
c.allowedClasses = nil
|
||||||
|
c.enforcementLevel = ""
|
||||||
c.resetDriftLocked()
|
c.resetDriftLocked()
|
||||||
return c.persistLocked()
|
return c.persistLocked()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func TestHappyPathDrivesStates(t *testing.T) {
|
|||||||
if err := c.EnterPlanning(); err != nil {
|
if err := c.EnterPlanning(); err != nil {
|
||||||
t.Fatalf("enter planning: %v", err)
|
t.Fatalf("enter planning: %v", err)
|
||||||
}
|
}
|
||||||
if err := c.StartManualCommitment("Port session", "session tests pass", 25*time.Minute, nil); err != nil {
|
if err := c.StartManualCommitment("Port session", "session tests pass", 25*time.Minute, nil, domain.EnforcementWarn); err != nil {
|
||||||
t.Fatalf("start commitment: %v", err)
|
t.Fatalf("start commitment: %v", err)
|
||||||
}
|
}
|
||||||
st := c.State()
|
st := c.State()
|
||||||
@@ -67,7 +67,7 @@ func TestHappyPathDrivesStates(t *testing.T) {
|
|||||||
func TestStartCommitmentRejectsInvalidInput(t *testing.T) {
|
func TestStartCommitmentRejectsInvalidInput(t *testing.T) {
|
||||||
c, _ := newTestController(t)
|
c, _ := newTestController(t)
|
||||||
_ = c.EnterPlanning()
|
_ = c.EnterPlanning()
|
||||||
if err := c.StartManualCommitment("", "x", 25*time.Minute, nil); err == nil {
|
if err := c.StartManualCommitment("", "x", 25*time.Minute, nil, domain.EnforcementWarn); err == nil {
|
||||||
t.Fatalf("empty next action should error")
|
t.Fatalf("empty next action should error")
|
||||||
}
|
}
|
||||||
if c.State().RuntimeState != domain.RuntimePlanning {
|
if c.State().RuntimeState != domain.RuntimePlanning {
|
||||||
@@ -82,7 +82,7 @@ func TestStateRestoresFromSnapshot(t *testing.T) {
|
|||||||
t.Fatalf("new: %v", err)
|
t.Fatalf("new: %v", err)
|
||||||
}
|
}
|
||||||
_ = first.EnterPlanning()
|
_ = first.EnterPlanning()
|
||||||
_ = first.StartManualCommitment("Persisted action", "done", 25*time.Minute, nil)
|
_ = first.StartManualCommitment("Persisted action", "done", 25*time.Minute, nil, domain.EnforcementWarn)
|
||||||
|
|
||||||
second, err := New(path)
|
second, err := New(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,7 +104,7 @@ func TestRestoredCommitmentKeepsDeadline(t *testing.T) {
|
|||||||
t.Fatalf("new: %v", err)
|
t.Fatalf("new: %v", err)
|
||||||
}
|
}
|
||||||
_ = first.EnterPlanning()
|
_ = first.EnterPlanning()
|
||||||
_ = first.StartManualCommitment("Keep deadline", "done", 25*time.Minute, nil)
|
_ = first.StartManualCommitment("Keep deadline", "done", 25*time.Minute, nil, domain.EnforcementWarn)
|
||||||
want := first.State().Commitment.DeadlineUnixSecs
|
want := first.State().Commitment.DeadlineUnixSecs
|
||||||
|
|
||||||
second, err := New(path)
|
second, err := New(path)
|
||||||
@@ -147,7 +147,7 @@ func TestAccumulatesBucketsAndSwitches(t *testing.T) {
|
|||||||
c.RecordWindow(snap("code", "antidrift")) // latest window before start
|
c.RecordWindow(snap("code", "antidrift")) // latest window before start
|
||||||
|
|
||||||
_ = c.EnterPlanning()
|
_ = c.EnterPlanning()
|
||||||
_ = c.StartManualCommitment("work", "done", 25*time.Minute, nil) // seeds at t=1000 with code/antidrift
|
_ = c.StartManualCommitment("work", "done", 25*time.Minute, nil, domain.EnforcementWarn) // seeds at t=1000 with code/antidrift
|
||||||
|
|
||||||
clk.advance(10 * time.Second)
|
clk.advance(10 * time.Second)
|
||||||
c.RecordWindow(snap("firefox", "docs")) // credits 10s to code/antidrift, switch -> firefox
|
c.RecordWindow(snap("firefox", "docs")) // credits 10s to code/antidrift, switch -> firefox
|
||||||
@@ -182,7 +182,7 @@ func TestUnavailableAccruesToReservedBucket(t *testing.T) {
|
|||||||
clk := &fakeClock{now: time.Unix(1000, 0)}
|
clk := &fakeClock{now: time.Unix(1000, 0)}
|
||||||
c.SetClock(clk.fn())
|
c.SetClock(clk.fn())
|
||||||
_ = c.EnterPlanning()
|
_ = c.EnterPlanning()
|
||||||
_ = c.StartManualCommitment("work", "done", 25*time.Minute, nil) // seed: empty unavailable latestWindow
|
_ = c.StartManualCommitment("work", "done", 25*time.Minute, nil, domain.EnforcementWarn) // seed: empty unavailable latestWindow
|
||||||
// latestWindow was zero-value (unavailable) at seed time.
|
// latestWindow was zero-value (unavailable) at seed time.
|
||||||
clk.advance(5 * time.Second)
|
clk.advance(5 * time.Second)
|
||||||
c.RecordWindow(snap("code", "x")) // credits 5s to the reserved bucket
|
c.RecordWindow(snap("code", "x")) // credits 5s to the reserved bucket
|
||||||
@@ -199,7 +199,7 @@ func TestCrashReplayRebuildsStats(t *testing.T) {
|
|||||||
first.SetClock(clk.fn())
|
first.SetClock(clk.fn())
|
||||||
first.RecordWindow(snap("code", "antidrift"))
|
first.RecordWindow(snap("code", "antidrift"))
|
||||||
_ = first.EnterPlanning()
|
_ = first.EnterPlanning()
|
||||||
_ = first.StartManualCommitment("work", "done", 25*time.Minute, nil)
|
_ = first.StartManualCommitment("work", "done", 25*time.Minute, nil, domain.EnforcementWarn)
|
||||||
clk.advance(15 * time.Second)
|
clk.advance(15 * time.Second)
|
||||||
first.RecordWindow(snap("firefox", "docs")) // 15s -> code, switch
|
first.RecordWindow(snap("firefox", "docs")) // 15s -> code, switch
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ func TestEndWritesAuditSummary(t *testing.T) {
|
|||||||
c.SetClock(clk.fn())
|
c.SetClock(clk.fn())
|
||||||
c.RecordWindow(snap("code", "antidrift"))
|
c.RecordWindow(snap("code", "antidrift"))
|
||||||
_ = c.EnterPlanning()
|
_ = c.EnterPlanning()
|
||||||
_ = c.StartManualCommitment("write plan", "plan done", 25*time.Minute, nil)
|
_ = c.StartManualCommitment("write plan", "plan done", 25*time.Minute, nil, domain.EnforcementWarn)
|
||||||
clk.advance(30 * time.Second)
|
clk.advance(30 * time.Second)
|
||||||
c.RecordWindow(snap("firefox", "docs"))
|
c.RecordWindow(snap("firefox", "docs"))
|
||||||
clk.advance(10 * time.Second)
|
clk.advance(10 * time.Second)
|
||||||
@@ -374,7 +374,7 @@ func TestStartCommitmentPersistsAllowedClasses(t *testing.T) {
|
|||||||
t.Fatalf("new: %v", err)
|
t.Fatalf("new: %v", err)
|
||||||
}
|
}
|
||||||
_ = first.EnterPlanning()
|
_ = first.EnterPlanning()
|
||||||
if err := first.StartManualCommitment("a", "b", 25*time.Minute, []string{"code"}); err != nil {
|
if err := first.StartManualCommitment("a", "b", 25*time.Minute, []string{"code"}, domain.EnforcementWarn); err != nil {
|
||||||
t.Fatalf("start: %v", err)
|
t.Fatalf("start: %v", err)
|
||||||
}
|
}
|
||||||
second, err := New(path)
|
second, err := New(path)
|
||||||
@@ -389,7 +389,7 @@ func TestStartCommitmentPersistsAllowedClasses(t *testing.T) {
|
|||||||
func TestOnTaskAppendsCurrentClass(t *testing.T) {
|
func TestOnTaskAppendsCurrentClass(t *testing.T) {
|
||||||
c, _ := newTestController(t)
|
c, _ := newTestController(t)
|
||||||
_ = c.EnterPlanning()
|
_ = c.EnterPlanning()
|
||||||
_ = c.StartManualCommitment("a", "b", 25*time.Minute, nil)
|
_ = c.StartManualCommitment("a", "b", 25*time.Minute, nil, domain.EnforcementWarn)
|
||||||
c.RecordWindow(evidence.WindowSnapshot{Class: "slack", Title: "chat", Health: evidence.EvidenceHealth{Available: true}})
|
c.RecordWindow(evidence.WindowSnapshot{Class: "slack", Title: "chat", Health: evidence.EvidenceHealth{Available: true}})
|
||||||
if err := c.OnTask(); err != nil {
|
if err := c.OnTask(); err != nil {
|
||||||
t.Fatalf("ontask: %v", err)
|
t.Fatalf("ontask: %v", err)
|
||||||
@@ -434,11 +434,16 @@ func waitDriftStatus(t *testing.T, c *Controller, want string) State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func startActive(t *testing.T, c *Controller, allowed []string) {
|
func startActive(t *testing.T, c *Controller, allowed []string) {
|
||||||
|
t.Helper()
|
||||||
|
startActiveLevel(t, c, allowed, domain.EnforcementWarn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func startActiveLevel(t *testing.T, c *Controller, allowed []string, level domain.EnforcementLevel) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if err := c.EnterPlanning(); err != nil {
|
if err := c.EnterPlanning(); err != nil {
|
||||||
t.Fatalf("planning: %v", err)
|
t.Fatalf("planning: %v", err)
|
||||||
}
|
}
|
||||||
if err := c.StartManualCommitment("write report", "report drafted", 25*time.Minute, allowed); err != nil {
|
if err := c.StartManualCommitment("write report", "report drafted", 25*time.Minute, allowed, level); err != nil {
|
||||||
t.Fatalf("start: %v", err)
|
t.Fatalf("start: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -541,7 +546,7 @@ func TestRestoredActiveSessionCanBeJudged(t *testing.T) {
|
|||||||
t.Fatalf("new: %v", err)
|
t.Fatalf("new: %v", err)
|
||||||
}
|
}
|
||||||
_ = first.EnterPlanning()
|
_ = first.EnterPlanning()
|
||||||
if err := first.StartManualCommitment("write report", "drafted", 25*time.Minute, []string{"code"}); err != nil {
|
if err := first.StartManualCommitment("write report", "drafted", 25*time.Minute, []string{"code"}, domain.EnforcementWarn); err != nil {
|
||||||
t.Fatalf("start: %v", err)
|
t.Fatalf("start: %v", err)
|
||||||
}
|
}
|
||||||
second, err := New(path)
|
second, err := New(path)
|
||||||
@@ -559,7 +564,7 @@ func TestLeavingPlanningClearsCoach(t *testing.T) {
|
|||||||
c.SetCoach(&fakeCoach{prop: ai.Proposal{NextAction: "x", SuccessCondition: "y", TimeboxSecs: 60}})
|
c.SetCoach(&fakeCoach{prop: ai.Proposal{NextAction: "x", SuccessCondition: "y", TimeboxSecs: 60}})
|
||||||
_ = c.RequestCoach("x")
|
_ = c.RequestCoach("x")
|
||||||
waitCoachStatus(t, c, "ready")
|
waitCoachStatus(t, c, "ready")
|
||||||
if err := c.StartManualCommitment("a", "b", 25*time.Minute, nil); err != nil {
|
if err := c.StartManualCommitment("a", "b", 25*time.Minute, nil, domain.EnforcementWarn); err != nil {
|
||||||
t.Fatalf("start: %v", err)
|
t.Fatalf("start: %v", err)
|
||||||
}
|
}
|
||||||
if c.State().Coach != nil {
|
if c.State().Coach != nil {
|
||||||
@@ -888,7 +893,7 @@ func TestStaleTasksFetchDiscardedAfterLeavingPlanning(t *testing.T) {
|
|||||||
waitTasksStatus(t, c, "pending")
|
waitTasksStatus(t, c, "pending")
|
||||||
|
|
||||||
// Step 2: leave planning via a commitment — the stale fetch is still blocked.
|
// Step 2: leave planning via a commitment — the stale fetch is still blocked.
|
||||||
if err := c.StartManualCommitment("task", "done", 25*time.Minute, nil); err != nil {
|
if err := c.StartManualCommitment("task", "done", 25*time.Minute, nil, domain.EnforcementWarn); err != nil {
|
||||||
t.Fatalf("start commitment: %v", err)
|
t.Fatalf("start commitment: %v", err)
|
||||||
}
|
}
|
||||||
if c.State().RuntimeState != domain.RuntimeActive {
|
if c.State().RuntimeState != domain.RuntimeActive {
|
||||||
@@ -1066,7 +1071,7 @@ func driveToReview(t *testing.T, c *Controller) {
|
|||||||
if err := c.EnterPlanning(); err != nil {
|
if err := c.EnterPlanning(); err != nil {
|
||||||
t.Fatalf("planning: %v", err)
|
t.Fatalf("planning: %v", err)
|
||||||
}
|
}
|
||||||
if err := c.StartManualCommitment("write plan", "plan done", 25*time.Minute, nil); err != nil {
|
if err := c.StartManualCommitment("write plan", "plan done", 25*time.Minute, nil, domain.EnforcementWarn); err != nil {
|
||||||
t.Fatalf("start: %v", err)
|
t.Fatalf("start: %v", err)
|
||||||
}
|
}
|
||||||
if err := c.Complete(); err != nil {
|
if err := c.Complete(); err != nil {
|
||||||
@@ -1158,7 +1163,7 @@ func TestCarryForwardSurvivesRestart(t *testing.T) {
|
|||||||
if err := first.EnterPlanning(); err != nil {
|
if err := first.EnterPlanning(); err != nil {
|
||||||
t.Fatalf("planning: %v", err)
|
t.Fatalf("planning: %v", err)
|
||||||
}
|
}
|
||||||
if err := first.StartManualCommitment("a", "b", 25*time.Minute, nil); err != nil {
|
if err := first.StartManualCommitment("a", "b", 25*time.Minute, nil, domain.EnforcementWarn); err != nil {
|
||||||
t.Fatalf("start: %v", err)
|
t.Fatalf("start: %v", err)
|
||||||
}
|
}
|
||||||
if err := first.Complete(); err != nil {
|
if err := first.Complete(); err != nil {
|
||||||
@@ -1181,3 +1186,27 @@ func TestCarryForwardSurvivesRestart(t *testing.T) {
|
|||||||
t.Fatalf("carry-forward not restored onto planning: %+v", st.Reflection)
|
t.Fatalf("carry-forward not restored onto planning: %+v", st.Reflection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEnforcementLevelPersists(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
path := filepath.Join(dir, "state.json")
|
||||||
|
first, err := New(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
first.SetClock(func() time.Time { return time.Unix(1000, 0) })
|
||||||
|
if err := first.EnterPlanning(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := first.StartManualCommitment("write report", "drafted", 25*time.Minute, []string{"code"}, domain.EnforcementBlock); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
second, err := New(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if got := second.EnforcementLevelForTest(); got != domain.EnforcementBlock {
|
||||||
|
t.Fatalf("enforcement level not restored: got %q want %q", got, domain.EnforcementBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ type Snapshot struct {
|
|||||||
ReflectionStatus string `json:"reflection_status,omitempty"`
|
ReflectionStatus string `json:"reflection_status,omitempty"`
|
||||||
ReflectionRecap string `json:"reflection_recap,omitempty"`
|
ReflectionRecap string `json:"reflection_recap,omitempty"`
|
||||||
CarryForward string `json:"carry_forward,omitempty"`
|
CarryForward string `json:"carry_forward,omitempty"`
|
||||||
|
|
||||||
|
EnforcementLevel domain.EnforcementLevel `json:"enforcement_level,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultPath returns ~/.antidrift/state.json.
|
// DefaultPath returns ~/.antidrift/state.json.
|
||||||
|
|||||||
+7
-1
@@ -12,6 +12,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"antidrift/internal/domain"
|
||||||
"antidrift/internal/session"
|
"antidrift/internal/session"
|
||||||
"antidrift/internal/statemachine"
|
"antidrift/internal/statemachine"
|
||||||
|
|
||||||
@@ -110,6 +111,7 @@ type commitmentRequest struct {
|
|||||||
SuccessCondition string `json:"success_condition"`
|
SuccessCondition string `json:"success_condition"`
|
||||||
TimeboxSecs int64 `json:"timebox_secs"`
|
TimeboxSecs int64 `json:"timebox_secs"`
|
||||||
AllowedWindowClasses []string `json:"allowed_window_classes"`
|
AllowedWindowClasses []string `json:"allowed_window_classes"`
|
||||||
|
Enforce bool `json:"enforce"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleCommitment(c *gin.Context) {
|
func (s *Server) handleCommitment(c *gin.Context) {
|
||||||
@@ -118,7 +120,11 @@ func (s *Server) handleCommitment(c *gin.Context) {
|
|||||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid json"})
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid json"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := s.ctrl.StartManualCommitment(req.NextAction, req.SuccessCondition, time.Duration(req.TimeboxSecs)*time.Second, req.AllowedWindowClasses)
|
level := domain.EnforcementWarn
|
||||||
|
if req.Enforce {
|
||||||
|
level = domain.EnforcementBlock
|
||||||
|
}
|
||||||
|
err := s.ctrl.StartManualCommitment(req.NextAction, req.SuccessCondition, time.Duration(req.TimeboxSecs)*time.Second, req.AllowedWindowClasses, level)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
s.armExpiry()
|
s.armExpiry()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user