Harden lease lifecycle durability
This commit is contained in:
@@ -22,11 +22,11 @@ var ErrInvalid = errors.New("invalid event")
|
||||
// task for this content; nothing was appended.
|
||||
var ErrDuplicate = errors.New("duplicate task ingestion")
|
||||
|
||||
// CurrentEventSchema is 2: schema 2 requires every event to declare its
|
||||
// authorizing Surface (see ValidateEvent), enforced at the store append
|
||||
// boundary. Schema 1 events already on disk replay unchanged — tolerant
|
||||
// reader, not upcast (spec open question #2).
|
||||
const CurrentEventSchema = 2
|
||||
// CurrentEventSchema is 3: schema 2 requires every event to declare its
|
||||
// authorizing Surface; schema 3 adds lease fencing epochs. Older events stay
|
||||
// readable so a deployment can recover its existing log before new writes
|
||||
// are emitted (the store derives a non-renewable legacy epoch on replay).
|
||||
const CurrentEventSchema = 3
|
||||
|
||||
type TaskState string
|
||||
|
||||
@@ -102,8 +102,13 @@ type SessionEvidence struct {
|
||||
CheckedAt time.Time `json:"checked_at,omitempty"`
|
||||
}
|
||||
type Lease struct {
|
||||
HarnessID string `json:"harness_id"`
|
||||
Until time.Time `json:"until"`
|
||||
HarnessID string `json:"harness_id"`
|
||||
// Epoch is an opaque fencing token minted for every assignment. Versions
|
||||
// change for ordinary lifecycle events; an epoch changes only when
|
||||
// ownership changes, so an old pane can never become current again after
|
||||
// a release/re-lease cycle.
|
||||
Epoch string `json:"epoch"`
|
||||
Until time.Time `json:"until"`
|
||||
}
|
||||
type Task struct {
|
||||
ID string `json:"id"`
|
||||
@@ -191,7 +196,18 @@ func ValidateEvent(e Event) error {
|
||||
if p == nil {
|
||||
return fmt.Errorf("%w: payload must be an object", ErrInvalid)
|
||||
}
|
||||
return ValidatePayload(e.Type, p)
|
||||
if err := ValidatePayload(e.Type, p); err != nil {
|
||||
return err
|
||||
}
|
||||
if e.SchemaVersion >= 3 {
|
||||
switch e.Type {
|
||||
case "TaskLeased", "TaskLeaseRenewed", "TaskPickupValidated":
|
||||
if v, ok := p["lease_epoch"].(string); !ok || strings.TrimSpace(v) == "" {
|
||||
return fmt.Errorf("%w: lease_epoch required", ErrInvalid)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func ValidateCreated(p map[string]any) error {
|
||||
for _, k := range []string{"source", "external_id", "project"} {
|
||||
|
||||
Reference in New Issue
Block a user