# CRD ordering gap — does cub-direct install CRDs before the resources that need them?

**UNOFFICIAL/EXPERIMENTAL.** Live receipt generated by `scripts/run-crd-ordering-gap.mjs`; do not hand-edit. Regenerate with `npm run crd-ordering:proof`.

**Claim.** The cub-direct (no-controller) path applies the OCI bundle with plain `kubectl apply`, which has no dependency ordering or wait. On a FIRST install of a chart that ships a CRD plus a CR of that CRD, the CR fails ('no matches for kind ... ensure CRDs are installed first') and is never created. Helm installs CRDs first; Argo (sync waves) and Flux (retry/health) order it; cub-direct does not.

The doctrine's third delivery path — **cub-direct** (pull the OCI bundle + `kubectl apply`) — applies objects in file order with no dependency ordering or wait. Proven live on a throwaway kind cluster with a bundle that ships a CRD + a CR of it:

| Action | Custom resource created? |
| --- | --- |
| `kubectl apply -f <bundle>` (CRD + CR together) | **no** — `error: resource mapping not found for name: "my-widget" namespace: "default" from "/var/folders/4l/8wvwwzxs3xl78749bmmqzzbw0000gp/T/crdgap-b` |
| apply CRD → `wait --for=condition=established` → apply CR | yes (the fix) |

Overall: **watch**. Confirmed: the cub-direct first install of a CRD-bearing bundle fails — the CR applies before the CRD is established. Ordering CRD-first + waiting fixes it. So the no-controller path must install CRDs first (or wait/retry), or use a controller. Same theme as the prune gap: cub-direct is apply-only.

- **Affected:** cub-direct / no-controller first install of CRD-bearing charts. **Not affected:** Helm (installs CRDs first), Argo CD (sync waves), Flux (retry/health).
- **The fix:** the no-controller applier must install CRDs first and wait for them to be established (or apply-retry), or hand off to a controller. The doctrine should say so.
- Companion to the prune gap — both are apply-only limitations of the cub-direct path. Receipt: `runs/crd-ordering-gap/receipt.yaml`.
