Merge Logic
The merge logic is the critical path in the API. It takes raw cluster documents and catalog entries and produces the computed response that Flux consumes. Understanding the merge is key to understanding the entire system.
Platform Components Merge
This is the most complex merge. It combines three data sources into a single response:
flowchart TD
A["Cluster Document"] --> D["Merge Logic"]
B["Component Catalog"] --> D
C["Cluster Patches"] --> D
D --> E["Flux Response<br/>{inputs: [...]}"]
A -.- A1["platform_components[]<br/>per-cluster overrides"]
B -.- B1["Default oci_tag, component_path,<br/>oci_url, depends_on"]
C -.- C1["patches[component_id]<br/>key-value overrides"]
Merge Rules
For each component in the cluster’s platform_components array:
| Field | Source | Rule |
|---|---|---|
id | Cluster component ref | Passed through |
enabled | Cluster component ref | Passed through |
component_path | Cluster override OR catalog default | Cluster override wins if non-null |
component_version | Catalog | Always from catalog |
cluster_env_enabled | Catalog | Always from catalog (template handles path appending) |
source.oci_url | Catalog | Always from catalog |
source.oci_tag | Cluster override OR catalog default | Cluster override wins if non-null |
depends_on | Catalog | Always from catalog |
patches | Cluster patches[component_id] | Empty {} if no patches for this component |
cluster.name | Cluster doc | From cluster’s cluster_name |
cluster.dns | Cluster doc | From cluster’s cluster_dns |
cluster.environment | Cluster doc | From cluster’s environment |
Merge Example
Given this cluster document:
{
"cluster_name": "us-east-prod-01",
"cluster_dns": "us-east-prod-01.k8s.example.com",
"environment": "prod",
"platform_components": [
{ "id": "cert-manager", "enabled": true, "oci_tag": null, "component_path": null },
{ "id": "grafana", "enabled": true, "oci_tag": "v1.0.0-1", "component_path": "observability/grafana/17.1.0" }
],
"patches": {
"grafana": { "GRAFANA_REPLICAS": "3" }
}
}
And this catalog:
[
{ "_id": "cert-manager", "component_path": "core/cert-manager/1.14.0", "oci_url": "oci://registry/repo", "oci_tag": "v1.0.0", "depends_on": [] },
{ "_id": "grafana", "component_path": "observability/grafana/17.0.0", "oci_url": "oci://registry/repo", "oci_tag": "v1.0.0", "depends_on": ["cert-manager"] }
]
The merge produces:
{
"inputs": [
{
"id": "cert-manager",
"component_path": "core/cert-manager/1.14.0",
"source": { "oci_url": "oci://registry/repo", "oci_tag": "v1.0.0" },
"patches": {},
"cluster": { "name": "us-east-prod-01", "dns": "us-east-prod-01.k8s.example.com", "environment": "prod" }
},
{
"id": "grafana",
"component_path": "observability/grafana/17.1.0",
"source": { "oci_url": "oci://registry/repo", "oci_tag": "v1.0.0-1" },
"depends_on": ["cert-manager"],
"patches": { "GRAFANA_REPLICAS": "3" },
"cluster": { "name": "us-east-prod-01", "dns": "us-east-prod-01.k8s.example.com", "environment": "prod" }
}
]
}
Notice:
- cert-manager uses catalog defaults for everything (cluster overrides are null)
- grafana uses cluster override for
oci_tag(v1.0.0-1) andcomponent_path(observability/grafana/17.1.0) - grafana gets the per-cluster patch (
GRAFANA_REPLICAS: "3")
Namespaces Merge
Namespaces now use a reference + lookup model:
flowchart TD
A["Cluster Document"] --> C["Merge Logic"]
B["Namespace Definitions"] --> C
C --> D["Flux Response"]
A -.- A1["namespaces[]<br/>id references"]
B -.- B1["id, labels, annotations"]
D -.- D1["Each namespace gets<br/>cluster block nested in"]
Merge steps:
- Read
cluster.namespaces[]as ID references. - Resolve each ID from the namespace definitions store.
- Return resolved namespace payload + nested
clusterblock (name,dns,environment). - Any missing referenced IDs are skipped in Flux response generation.
Rolebindings Merge
Rolebindings follow the same pattern as namespaces:
- Read
cluster.rolebindings[]as ID references. - Resolve each ID from the rolebinding definitions store.
- Return resolved rolebinding payload (
id,role,subjects[]) + nestedclusterblock. - Any missing referenced IDs are skipped in Flux response generation.
Why Merge Matters
The merge logic is what makes this system more than a simple proxy. It enables:
- Catalog defaults — define a component once, inherit everywhere
- Per-cluster overrides — pin a specific cluster to a hotfix version without affecting others
- Per-cluster patches — inject environment-specific values without touching the component definition
- Computed responses — the cluster gets exactly the state it needs, computed from multiple data sources
Without the merge, you would need to duplicate the full component definition per cluster — which is exactly the problem this architecture solves.