Skip to content

Commit da7f311

Browse files
committed
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 and updated documentation.
1 parent 60956b9 commit da7f311

9 files changed

Lines changed: 122 additions & 90 deletions

File tree

docs/api-operator-guide.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ A practical guide for deploying, configuring, and operating the HyperFleet API c
1717
- [Rules to accept/discard adapter reports](#rules-to-acceptdiscard-adapter-reports)
1818
- [Computing `observed_generation`](#computing-observed_generation)
1919
- [Computing `status.conditions[type==Ready].last_updated_time`](#computing-statusconditionstypereadylast_updated_time)
20-
- [Computing `status.conditions[type==Available].last_updated_time`](#computing-statusconditionstypeavailablelast_updated_time)
21-
- [Computing `last_transition_time` for both `Ready` and `Available`](#computing-last_transition_time-for-both-ready-and-available)
20+
- [Computing `status.conditions[type==LastKnownReconciled].last_updated_time`](#computing-statusconditionstypelastknownreconciledlast_updated_time)
21+
- [Computing `last_transition_time` for both `Ready` and `LastKnownReconciled`](#computing-last_transition_time-for-both-ready-and-lastknownreconciled)
2222
3. [Configuration Reference](#3-configuration-reference)
2323
- [Adapter Requirements (REQUIRED)](#31-adapter-requirements-required)
2424
- [Database Configuration](#32-database-configuration)
@@ -108,7 +108,7 @@ Resource (e.g., Cluster)
108108

109109
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.
110110

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`).
112112

113113
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.
114114

@@ -147,7 +147,7 @@ GET /api/hyperfleet/v1/clusters/{id}
147147
"status": {
148148
"conditions": [
149149
{
150-
"type": "Available",
150+
"type": "LastKnownReconciled",
151151
"status": "True",
152152
"observed_generation": 1,
153153
"last_transition_time": "2026-03-10T07:56:35Z"
@@ -164,7 +164,7 @@ GET /api/hyperfleet/v1/clusters/{id}
164164
"updated_time": "2026-03-10T07:56:35Z"
165165
}
166166

167-
→ API returns aggregated status with Available and Ready conditions
167+
→ API returns aggregated status with LastKnownReconciled and Ready conditions
168168

169169
# 3. View adapter statuses
170170
GET /api/hyperfleet/v1/clusters/{id}/statuses
@@ -323,7 +323,7 @@ HyperFleet API aggregates the condition values reported by adapters associated w
323323
| Condition | Meaning | When True |
324324
|-----------|---------|-----------|
325325
| **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) |
326+
| **LastKnownReconciled** | Resource is operational at any known good configuration | All registered adapters report `Available=True` (at any generation) |
327327

328328
**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.
329329

@@ -337,16 +337,16 @@ The resource `status.conditions` array contains:
337337
- `True`: All required adapters `conditions[type=Available].status==True` at current spec generation
338338
- `False`: Any other combination of conditions
339339

340-
- **Available** - The resource is reconciled at a generation of the spec, current or past
340+
- **LastKnownReconciled** - The resource is reconciled at a generation of the spec, current or past
341341
- This condition is stateful meaning that is computed taking into account its previous values of `status` and `observed_generation`
342342
- This condition is "best effort", since there are cases that can not be covered correctly.
343343
- `True`:
344344
- All required adapters `conditions[type=Available].status==True` for the same `observed_generation`
345345
- Current value `status==True` and required adapters `conditions[type=Available]` at mixed `observed_generation`
346346
- `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
347+
- e.g. `LastKnownReconciled=True` for `observed_generation==1`
348+
- One adapter reports `Available=False` for `observed_generation=1` `LastKnownReconciled` transitions to `False`
349+
- One adapter reports `Available=False` for `observed_generation=2` `LastKnownReconciled` keeps its `True` status
350350

351351
- One **per-adapter** condition for each required adapter that has reported, mirroring the adapter's `conditions[type=Available]`:
352352
- `type`: Derived from the adapter name — PascalCase with `Successful` suffix (e.g., `adapter1` → `Adapter1Successful`, `my-adapter` → `MyAdapterSuccessful`)
@@ -392,7 +392,7 @@ These are API examples for a resource and resource statuses:
392392
"last_transition_time": "2021-01-01T10:00:00Z"
393393
},
394394
{
395-
"type": "Available",
395+
"type": "LastKnownReconciled",
396396
"status": "True",
397397
"reason": "All adapters reported Available True for the same generation",
398398
"message": "All adapters reported Available True for the same generation",
@@ -497,23 +497,23 @@ These are API examples for a resource and resource statuses:
497497
When a resource is created:
498498

499499
- 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`
500+
- `observed_generation` for `Ready` and `LastKnownReconciled` aggregated conditions is 1
501+
- `last_updated_time` and `last_transition_time` for `Ready` and `LastKnownReconciled` aggregated conditions is `resource.last_updated_time`
502502

503503
When a resource is changed:
504504

505505
- `resource.generation` gets incremented and aggregated conditions are re-evaluated
506506
- `status.conditions[type==Ready].observed_generation` always follows `resource.generation`
507-
- `status.conditions[type==Available].observed_generation` changes when all required adapters `condition[type==Available].observed_generation==resource.generation` otherwise remains unchanged.
507+
- `status.conditions[type==LastKnownReconciled].observed_generation` changes when all required adapters `condition[type==Available].observed_generation==resource.generation` otherwise remains unchanged.
508508

509509
##### Computing `observed_generation`
510510

511511
- For `Ready` it always matches `resource.generation`
512-
- For `Available`:
512+
- For `LastKnownReconciled`:
513513
- If all required adapters have a common `observed_generation` it will match the common value
514514
- 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)`
515+
- If `LastKnownReconciled` is `True`, `observed_generation` remains at its current value
516+
- If `LastKnownReconciled` is `False`, `observed_generation` will get the value of the `max(condition[type==Available].observed_generation)`
517517

518518
##### Computing `status.conditions[type==Ready].last_updated_time`
519519

@@ -526,14 +526,14 @@ The meaning of `last_updated_time` in the aggregated conditions refers to the ne
526526
- Why do we want to keep the "oldest" value? because if it is too old, we need to trigger a reconciliation
527527
- 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)`
528528

529-
##### Computing `status.conditions[type==Available].last_updated_time`
529+
##### Computing `status.conditions[type==LastKnownReconciled].last_updated_time`
530530

531531
- 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)`
532532
- If not all required adapters have `condition[type==Available].observed_generation` at the same value:
533533
- 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`
534534
- In any other case `last_updated_time` is kept unchanged
535535

536-
##### Computing `last_transition_time` for both `Ready` and `Available`
536+
##### Computing `last_transition_time` for both `Ready` and `LastKnownReconciled`
537537

538538
- Meaning is last time this condition’s status (True / False) changed, regardless of the existing and new `observed_generation`
539539
- This property is stateful since it relies on the existing value to determine if there has been a transition

docs/api-resources.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ POST /api/hyperfleet/v1/clusters/{cluster_id}/statuses
5353
"status": {
5454
"conditions": [
5555
{
56-
"type": "Available",
56+
"type": "LastKnownReconciled",
5757
"status": "False",
5858
"reason": "AwaitingAdapters",
5959
"message": "Waiting for adapters to report status",
@@ -79,7 +79,7 @@ POST /api/hyperfleet/v1/clusters/{cluster_id}/statuses
7979

8080
</details>
8181

82-
**Note**: Status initially has `Available=False` and `Ready=False` conditions until adapters report status.
82+
**Note**: Status initially has `LastKnownReconciled=False` and `Ready=False` conditions until adapters report status.
8383

8484
### Get Cluster
8585

@@ -108,7 +108,7 @@ POST /api/hyperfleet/v1/clusters/{cluster_id}/statuses
108108
"status": {
109109
"conditions": [
110110
{
111-
"type": "Available",
111+
"type": "LastKnownReconciled",
112112
"status": "True",
113113
"reason": "ResourceAvailable",
114114
"message": "Cluster is accessible",
@@ -304,7 +304,7 @@ POST /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses
304304
"status": {
305305
"conditions": [
306306
{
307-
"type": "Available",
307+
"type": "LastKnownReconciled",
308308
"status": "False",
309309
"reason": "AwaitingAdapters",
310310
"message": "Waiting for adapters to report status",
@@ -361,7 +361,7 @@ POST /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses
361361
"status": {
362362
"conditions": [
363363
{
364-
"type": "Available",
364+
"type": "LastKnownReconciled",
365365
"status": "True",
366366
"reason": "ResourceAvailable",
367367
"message": "NodePool is accessible",
@@ -446,7 +446,7 @@ See **[search.md](search.md)** for complete documentation.
446446
The status object contains synthesized conditions computed from adapter reports:
447447

448448
- `conditions` - Array of resource conditions, including:
449-
- **Available** - Whether resource is running at any known good configuration
449+
- **LastKnownReconciled** - Whether resource is running at any known good configuration
450450
- **Ready** - Whether all adapters have processed current spec generation
451451
- Additional conditions from adapters (with `observed_generation`, timestamps)
452452

docs/search.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,14 @@ Label keys must contain only lowercase letters (a-z), digits (0-9), and undersco
9898

9999
Query resources by status conditions: `status.conditions.<Type>='<Status>'`
100100

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.
102102

103103
**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'`).
104104

105105
```bash
106106
# Find available clusters
107107
curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \
108-
--data-urlencode "search=status.conditions.Available='True'"
108+
--data-urlencode "search=status.conditions.LastKnownReconciled='True'"
109109

110110
# Find clusters that are not ready
111111
curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \

openapi/openapi.yaml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ paths:
5050
5151
**Note**: The `status` object in the response is read-only and computed by the service.
5252
It is NOT part of the request body. Initially,
53-
status.conditions will include mandatory "Available", "Ready" and "Reconciled" conditions.
53+
status.conditions will include mandatory "LastKnownReconciled", "Ready" and "Reconciled" conditions.
5454
parameters: []
5555
responses:
5656
'201':
@@ -189,7 +189,7 @@ paths:
189189
created_time: '2021-01-01T10:00:00Z'
190190
last_updated_time: '2021-01-01T10:00:00Z'
191191
last_transition_time: '2021-01-01T10:00:00Z'
192-
- type: Available
192+
- type: LastKnownReconciled
193193
status: 'True'
194194
reason: All adapters reported Available True for the same generation
195195
message: All adapters reported Available True for the same generation
@@ -394,7 +394,7 @@ paths:
394394
created_time: '2021-01-01T10:00:00Z'
395395
last_updated_time: '2021-01-01T10:00:00Z'
396396
last_transition_time: '2021-01-01T10:00:00Z'
397-
- type: Available
397+
- type: LastKnownReconciled
398398
status: 'True'
399399
reason: All adapters reported Available True for the same generation
400400
message: All adapters reported Available True for the same generation
@@ -1075,7 +1075,7 @@ components:
10751075
created_time: '2021-01-01T10:00:00Z'
10761076
last_updated_time: '2021-01-01T10:00:00Z'
10771077
last_transition_time: '2021-01-01T10:00:00Z'
1078-
- type: Available
1078+
- type: LastKnownReconciled
10791079
status: 'True'
10801080
reason: All adapters reported Available True for the same generation
10811081
message: All adapters reported Available True for the same generation
@@ -1199,7 +1199,7 @@ components:
11991199
**Mandatory conditions**:
12001200
- `type: "Ready"` *(deprecated — use Reconciled)*: Whether all adapters report successfully at the current generation.
12011201
- `type: "Reconciled"`: Whether the resource's desired state has been fully reconciled by all adapters at the current generation.
1202-
- `type: "Available"`: Aggregated adapter result for a common observed_generation.
1202+
- `type: "LastKnownReconciled"`: Aggregated adapter result for a common observed_generation. Sticky — stays True as long as all required adapters were reconciled at a common observed generation, even if a new generation is being processed.
12031203
12041204
These conditions are present immediately upon resource creation.
12051205
description: |-
@@ -1374,7 +1374,7 @@ components:
13741374
created_time: '2021-01-01T10:00:00Z'
13751375
last_updated_time: '2021-01-01T10:00:00Z'
13761376
last_transition_time: '2021-01-01T10:00:00Z'
1377-
- type: Available
1377+
- type: LastKnownReconciled
13781378
status: 'True'
13791379
reason: All adapters reported Available True for the same generation
13801380
message: All adapters reported Available True for the same generation
@@ -1565,7 +1565,7 @@ components:
15651565
**Mandatory conditions**:
15661566
- `type: "Ready"` *(deprecated — use Reconciled)*: Whether all adapters report successfully at the current generation.
15671567
- `type: "Reconciled"`: Whether the resource's desired state has been fully reconciled by all adapters at the current generation.
1568-
- `type: "Available"`: Aggregated adapter result for a common observed_generation.
1568+
- `type: "LastKnownReconciled"`: Aggregated adapter result for a common observed_generation. Sticky — stays True as long as all required adapters were reconciled at a common observed generation, even if a new generation is being processed.
15691569
15701570
These conditions are present immediately upon resource creation.
15711571
description: |-

pkg/api/status_types.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@ func (s AdapterConditionStatus) IsValid() bool {
2828

2929
// Condition type constants
3030
const (
31-
ConditionTypeAvailable = "Available"
32-
ConditionTypeApplied = "Applied"
33-
ConditionTypeHealth = "Health"
34-
ConditionTypeReady = "Ready"
35-
ConditionTypeReconciled = "Reconciled"
36-
ConditionTypeFinalized = "Finalized"
31+
ConditionTypeAvailable = "Available"
32+
ConditionTypeLastKnownReconciled = "LastKnownReconciled"
33+
ConditionTypeApplied = "Applied"
34+
ConditionTypeHealth = "Health"
35+
ConditionTypeReady = "Ready"
36+
ConditionTypeReconciled = "Reconciled"
37+
ConditionTypeFinalized = "Finalized"
3738
)
3839

3940
// ResourceCondition represents a condition of a resource

0 commit comments

Comments
 (0)