Root cause: the application-controller rendered the per-Application
HelmRelease with `metadata.namespace = Org` and `spec.targetNamespace
= Org` where Org is the parent Organization slug. On omantel the
Application(qa-wp) lives in ns `qa-omantel` while the Org is named
`omantel-platform` — so the workload Pod landed in the wrong namespace,
breaking matrix rows TC-068 / TC-100 / TC-204 / TC-262 / TC-263 (all
asserting Pod in qa-omantel). Symmetric Kustomization wrapper had the
same bug. Existing render unit test only covered the org==namespace
case (`acme/acme`) which masked the bug.
Fix:
- render.Inputs gains AppNamespace field. helmRelease + kustomization
templates resolve `metadata.namespace` and `spec.targetNamespace` to
AppNamespace (back-compat default = Org).
- application_controller.go passes app.GetNamespace() as AppNamespace
on every render.Render call.
- HelmRelease spec.install.createNamespace = true so a missing workload
namespace is provisioned by helm-controller (per
docs/INVIOLABLE-PRINCIPLES.md #1 target-state — controller must work
without an operator pre-creating the namespace).
- Org slug is still stamped on the catalyst.openova.io/organization
label for traceability.
- 3 new Go tests:
TestRender_NamespaceIsAppNamespace (omantel scenario via render pkg)
TestRender_CreateNamespaceTrue
TestReconcile_HelmReleaseTargetNamespaceIsAppNamespace (drives the
omantel scenario end-to-end through the controller fake)
- build-application-controller.yaml extended with auto-bump of
controllers.application.image.tag in values.yaml on push-to-main, so
the chart picks up the rebuilt image without a manual operator edit
(per feedback_no_mvp_no_workarounds.md rule 1).
- bp-catalyst-platform chart 1.4.114 → 1.4.115.
Verification (post-roll on omantel):
- delete omantel-platform/qa-wp Pod
- annotate qa-omantel/qa-wp HR for reconcile
- expect: Pod in qa-omantel ns + HR.spec.targetNamespace == qa-omantel
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>