close worktree transport and lifecycle contract gaps
This commit is contained in:
@@ -185,6 +185,17 @@ func (s *Store) Append(e domain.Event) error {
|
||||
if taskExists && e.Version != t.Version+1 {
|
||||
return domain.ErrConflict
|
||||
}
|
||||
// Every optimistic lifecycle writer may carry its observed version. Enforce
|
||||
// it at the append boundary so non-HTTP producers receive the same CAS.
|
||||
var contract map[string]any
|
||||
if err := json.Unmarshal(e.Payload, &contract); err != nil {
|
||||
return err
|
||||
}
|
||||
if expected, ok := contract["expected_version"].(float64); ok {
|
||||
if expected != float64(int(expected)) || !taskExists || int(expected) != t.Version {
|
||||
return domain.ErrConflict
|
||||
}
|
||||
}
|
||||
if e.Type == "TaskLeased" {
|
||||
var p struct {
|
||||
ExpectedVersion *int `json:"expected_version"`
|
||||
|
||||
@@ -92,3 +92,18 @@ func TestLifecycleEventsRequireEvidence(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpectedVersionIsCheckedForEveryWriter(t *testing.T) {
|
||||
s, err := Open(t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := s.Append(created("create")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p := json.RawMessage(`{"reason":"rotate","expected_version":0}`)
|
||||
err = s.Append(domain.Event{Type: "TaskReleased", TaskID: "task-1", Version: 2, Payload: p})
|
||||
if err != domain.ErrConflict {
|
||||
t.Fatalf("expected CAS conflict, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user