You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
HYPERFLEET-1017 - refactor: rename aggregated Available condition to LastKnownReconciled
Rename the API-computed aggregated condition from Available to
LastKnownReconciled. The adapter-level Available condition remains
unchanged. Includes backward compatibility for legacy DB records,
differentiated reason/message for false conditions, minItems: 3
enforcement in OpenAPI schemas, and updated documentation.
2.**Automatic Version Tracking (generation)**: Every time you update the `spec`, the API automatically increments the `generation` counter. This allows distributed adapters to detect when they need to reconcile infrastructure changes.
110
110
111
-
3.**Observed State (status)**: Adapters report their progress and results back to the API via status endpoints. The API aggregates these reports into unified resource-level conditions (e.g., `Ready`, `Available`).
111
+
3.**Observed State (status)**: Adapters report their progress and results back to the API via status endpoints. The API aggregates these reports into unified resource-level conditions (e.g., `Ready`, `LastKnownReconciled`).
112
112
113
113
4.**Filtering (labels)**: Labels are key-value pairs you can attach to resources for organization and filtering (e.g., `environment: production`, `region: us-east-1`). E.g., Sentinel instances can define resource selectors based on labels to watch specific subsets of resources, enabling horizontal scaling across multiple Sentinel deployments.
114
114
@@ -147,7 +147,13 @@ GET /api/hyperfleet/v1/clusters/{id}
147
147
"status": {
148
148
"conditions": [
149
149
{
150
-
"type": "Available",
150
+
"type": "Reconciled",
151
+
"status": "True",
152
+
"observed_generation": 1,
153
+
"last_transition_time": "2026-03-10T07:56:35Z"
154
+
},
155
+
{
156
+
"type": "LastKnownReconciled",
151
157
"status": "True",
152
158
"observed_generation": 1,
153
159
"last_transition_time": "2026-03-10T07:56:35Z"
@@ -164,7 +170,7 @@ GET /api/hyperfleet/v1/clusters/{id}
164
170
"updated_time": "2026-03-10T07:56:35Z"
165
171
}
166
172
167
-
→ API returns aggregated status with Available and Ready conditions
173
+
→ API returns aggregated status with Reconciled, LastKnownReconciled, and Ready conditions
168
174
169
175
# 3. View adapter statuses
170
176
GET /api/hyperfleet/v1/clusters/{id}/statuses
@@ -323,7 +329,7 @@ HyperFleet API aggregates the condition values reported by adapters associated w
323
329
| Condition | Meaning | When True |
324
330
|-----------|---------|-----------|
325
331
| **Ready** | Resource is fully reconciled at current spec | All registered adapters report `Available=True` at the **current** `resource.spec.generation` |
326
-
| **Available** | Resource is operational at any known good configuration | All registered adapters report `Available=True` (at any generation) |
332
+
| **LastKnownReconciled** | Resource is operational at any known good configuration | All registered adapters report `Available=True` for a common `observed_generation`, or sticky-true is preserved when adapters are transitioning to a new generation |
327
333
328
334
**Note**: The meaning of the field `last_updated_time` for the aggregated conditions has special meaning. It doesn't reflect the last time it was updated from adapters but the OLDEST time it can be considered to be valid.
329
335
@@ -337,16 +343,16 @@ The resource `status.conditions` array contains:
337
343
- `True`: All required adapters `conditions[type=Available].status==True` at current spec generation
338
344
- `False`: Any other combination of conditions
339
345
340
-
- **Available** - The resource is reconciled at a generation of the spec, current or past
346
+
- **LastKnownReconciled** - The resource is reconciled at a generation of the spec, current or past
341
347
- This condition is stateful meaning that is computed taking into account its previous values of `status` and `observed_generation`
342
348
- This condition is "best effort", since there are cases that can not be covered correctly.
343
349
- `True`:
344
350
- All required adapters `conditions[type=Available].status==True` for the same `observed_generation`
345
351
- Current value `status==True` and required adapters `conditions[type=Available]` at mixed `observed_generation`
346
352
- `False`: Any other combination of conditions
347
-
- e.g. `Available=True` for `observed_generation==1`
348
-
- One adapter reports `Available=False` for `observed_generation=1` `Available` transitions to `False`
349
-
- One adapter reports `Available=False` for `observed_generation=2` `Available` keeps its `True` status
353
+
- e.g. `LastKnownReconciled=True` for `observed_generation==1`
354
+
- One adapter reports `Available=False` for `observed_generation=1` `LastKnownReconciled` transitions to `False`
355
+
- One adapter reports `Available=False` for `observed_generation=2` `LastKnownReconciled` keeps its `True` status
350
356
351
357
- One **per-adapter** condition for each required adapter that has reported, mirroring the adapter's `conditions[type=Available]`:
352
358
- `type`: Derived from the adapter name — PascalCase with `Successful` suffix (e.g., `adapter1` → `Adapter1Successful`, `my-adapter` → `MyAdapterSuccessful`)
@@ -392,10 +398,10 @@ These are API examples for a resource and resource statuses:
392
398
"last_transition_time": "2021-01-01T10:00:00Z"
393
399
},
394
400
{
395
-
"type": "Available",
401
+
"type": "LastKnownReconciled",
396
402
"status": "True",
397
-
"reason": "All adapters reported Available True for the same generation",
398
-
"message": "All adapters reported AvailableTrue for the same generation",
403
+
"reason": "AllAdaptersReconciled",
404
+
"message": "All required adapters report Available=True for the tracked generation",
399
405
"observed_generation": 1,
400
406
"created_time": "2021-01-01T10:00:00Z",
401
407
"last_updated_time": "2021-01-01T10:00:00Z",
@@ -497,23 +503,23 @@ These are API examples for a resource and resource statuses:
497
503
When a resource is created:
498
504
499
505
- Initial `generation` is 1 and aggregated conditions are evaluated
500
-
- `observed_generation`for `Ready` and `Available` aggregated conditions is 1
501
-
- `last_updated_time`and `last_transition_time` for `Ready` and `Available` aggregated conditions is `resource.last_updated_time`
506
+
- `observed_generation`for `Ready` and `LastKnownReconciled` aggregated conditions is 1
507
+
- `last_updated_time`and `last_transition_time` for `Ready` and `LastKnownReconciled` aggregated conditions is `resource.last_updated_time`
502
508
503
509
When a resource is changed:
504
510
505
511
- `resource.generation`gets incremented and aggregated conditions are re-evaluated
- `status.conditions[type==Available].observed_generation`changes when all required adapters `condition[type==Available].observed_generation==resource.generation` otherwise remains unchanged.
513
+
- `status.conditions[type==LastKnownReconciled].observed_generation`changes when all required adapters `condition[type==Available].observed_generation==resource.generation` otherwise remains unchanged.
508
514
509
515
##### Computing `observed_generation`
510
516
511
517
- For `Ready` it always matches `resource.generation`
512
-
- For `Available`:
518
+
- For `LastKnownReconciled`:
513
519
- If all required adapters have a common `observed_generation` it will match the common value
514
520
- If required adapters have mixed `observed_generation`
515
-
- If `Available` is `True`, `observed_generation` remains at its current value
516
-
- If `Available` is `False`, `observed_generation` will get the value of the `max(condition[type==Available].observed_generation)`
521
+
- If `LastKnownReconciled` is `True`, `observed_generation` remains at its current value
522
+
- If `LastKnownReconciled` is `False`, `observed_generation` will get the value of the `max(condition[type==Available].observed_generation)`
@@ -526,14 +532,14 @@ The meaning of `last_updated_time` in the aggregated conditions refers to the ne
526
532
- Why do we want to keep the "oldest" value? because if it is too old, we need to trigger a reconciliation
527
533
- When some required adapter conditions `condition[type==Available].observed_generation==resource.generation` then `last_updated_time=min(statuses[].conditions[type==Available && observed_generation==resource.generation].observed_time)`
- If all required adapters have `condition[type==Available].observed_generation` at the same value then `last_updated_time=min(statuses[].conditions[type==Available].observed_time)`
532
538
- If not all required adapters have `condition[type==Available].observed_generation` at the same value:
533
539
- If any adapter at current `observed_generation==X` has `conditions[type==Available].status==False` then `last_updated_time=min(adapters[type==Available && observed_generation==X].observed_time`
534
540
- In any other case `last_updated_time` is kept unchanged
535
541
536
-
##### Computing `last_transition_time` for both `Ready` and `Available`
542
+
##### Computing `last_transition_time` for both `Ready` and `LastKnownReconciled`
537
543
538
544
- Meaning is last time this condition’s status (True / False) changed, regardless of the existing and new `observed_generation`
539
545
- This property is stateful since it relies on the existing value to determine if there has been a transition
Copy file name to clipboardExpand all lines: docs/search.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -98,14 +98,14 @@ Label keys must contain only lowercase letters (a-z), digits (0-9), and undersco
98
98
99
99
Query resources by status conditions: `status.conditions.<Type>='<Status>'`
100
100
101
-
Condition types must be PascalCase (`Ready`, `Available`) and status must be `True` or `False` for resource conditions.
101
+
Condition types must be PascalCase (`Ready`, `LastKnownReconciled`) and status must be `True` or `False` for resource conditions.
102
102
103
103
**Note:** Only the `=` operator is supported for condition queries. Other operators (`!=`, `<`, `>`, `in`, etc.) will return an error. The `NOT` operator is not supported with condition queries (`status.conditions.<Type>` or `status.conditions.<Type>.<Subfield>`) and will return a `400 Bad Request` error. Use the inverse condition value instead (e.g., `status.conditions.Ready='False'` rather than `NOT status.conditions.Ready='True'`).
0 commit comments