canonical / canonical/charm-integration-testing
bundle_builder_x: cross_model_mesh is wired as a standalone interface, but it is a companion-only metadata channel
- Dominant language
- Python
- Stars
- 6
- Forks
- 1
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 98
Description
> Filed by an AI agent on behalf of @canonical/solutions-qa during test failure triage. Please verify details before acting.
### Problem statement
`cross_model_mesh` (`provide-cmr-mesh` / `require-cmr-mesh`) is currently treated by both the test-plan generator and `bundle_builder_x` as an ordinary pairable interface, like `grafana_dashboard` or `metrics-endpoint`. It is not: per the interface's own documentation (`canonical/service-mesh`, `docs/explanation/cross-model-mesh.md`) and `validators/cross_model_mesh/validator.py`, `cross_model_mesh` carries no application traffic. It exists solely as a metadata side-channel so `istio-beacon-k8s` can build correct `AuthorizationPolicy` source identities for an **already-existing, genuinely cross-model** relation between the same two applications, riding the *same* Juju offer. It has no meaning as a standalone integration and no meaning at all in a single-model deployment.
Querying Test Observer's test plans (`get_test_plans(q="cross_model_mesh")`) currently returns **303 distinct test plans** that pair `provide-cmr-mesh`/`require-cmr-mesh` directly between arbitrary charm pairs across the observability/kubeflow ecosystem, e.g.:
- `admission-webhook:provide-cmr-mesh/cross_model_mesh/alertmanager-k8s:require-cmr-mesh`
- `alertmanager-k8s:provide-cmr-mesh/cross_model_mesh/kfp-ui:require-cmr-mesh`
None of these charm pairs have any other relationship to each other; there is no real cross-model relation for the mesh metadata to describe.
A concrete instance of the resulting bad bundle: test execution 919485 (mongodb-k8s revision 231/edge, test plan `mongodb-k8s:grafana-dashboard/grafana_dashboard/opentelemetry-collector-k8s:grafana-dashboards-consumer`) deploys a **single-model** environment (no Juju offers/SAAS present), yet `bundle_builder_x` wires two `cross_model_mesh` relations into the same bundle:
- `opentelemetry-collector-k8s:provide-cmr-mesh <-> grafana-k8s:require-cmr-mesh`
- `parca-k8s:provide-cmr-mesh <-> opentelemetry-collector-k8s:require-cmr-mesh` (with **no other relation at all** between `parca-k8s` and `opentelemetry-collector-k8s`)
Test Observer link: https://test-observer.canonical.com/#/charms/411048?testExecutionId=919485&testResultId=13470140
This is a variant of the invalid-test-plan class already described in #887, but specific to `cross_model_mesh`'s companion-only semantics.
### Enhancement Proposal
Two complementary mechanisms, both scoped to `bundle_builder_x`:
1. **Reject invalid standalone pairings.** Tag `provide-cmr-mesh`/`require-cmr-mesh` endpoints (via the existing per-endpoint `features` override mechanism) and extend the constraint solver so that a `cross_model_mesh` integration is only satisfiable when it accompanies a genuine, already cross-model relation between the same two applications (on the same offer). A standalone/local-only `cross_model_mesh` pairing should make the bundle build fail cleanly (`UncompletableBundleError` or equivalent) rather than silently producing an invalid bundle that fails at runtime. Once this is in place, the ~303 test plans that only ever request a standalone `cross_model_mesh` pairing will fail deterministically at bundle-build time; a filtered Test Observer **attachment rule** can then auto-attach a single explanatory issue to these, instead of requiring manual per-execution triage.
2. **Add a constraint primitive for the mandatory direction.** `bundle_builder_x`'s internal domain model already has `Domain.is_cross_model(integration)`, used today inside `_reachable_set`'s Z3 lowering (`dsl_lowering.py`). Expose an equivalent primitive in the public constraint DSL (`constraints_dsl.py`), e.g. `cross_model(endpoint[x])`, so per-charm override YAML can express the converse rule: whenever a real interface *is* actually integrated across models, `provide-cmr-mesh`/`require-cmr-mesh` becomes **required**, not merely optional — e.g.:
```
cross_model(endpoint[grafana-dashboard]) => bool(endpoint[provide-cmr-mesh])
```
This replaces today's per-charm, per-track "mark it optional and hope the solver only wires it opportunistically when needed" pattern (see `static/charm-overrides/grafana-k8s.yaml`, `static/charm-overrides/opentelemetry-collector-k8s.yaml`) with a rule that is both stricter (rejects invalid local wiring) and more complete (mandates it when genuinely needed).
### What needs to get done?
- [ ] Add a `features`/constraint-based rejection rule to `bundle_builder_x` so `cross_model_mesh` integrations are unsatisfiable unless they accompany a genuine cross-model relation between the same two apps on the same offer.
- [ ] Add a `cross_model(endpoint[x])` primitive to the constraint DSL (parser in `constraints_dsl.py`, lowering in `dsl_lowering.py`), backed by the existing `Domain.is_cross_model()`.
- [ ] Update `static/charm-overrides/*.yaml` for charms with `cross_model_mesh` endpoints (e.g. `grafana-k8s`, `opentelemetry-collector-k8s`, `parca-k8s`, `alertmanager-k8s`, `istio-beacon-k8s`) to use the new mandatory-when-CMR constraint instead of a bare `optional: true`.
- [ ] Once bundle-build failures for invalid standalone `cross_model_mesh` pairings are deterministic, create a filtered Test Observer attachment rule to auto-triage the affected test plans.
Contributor guide
Research direction
Start with constraints_dsl.py and dsl_lowering.py, then inspect Domain.is_cross_model() and the existing bundle_builder_x constraint handling. Review the cross_model_mesh overrides in static/charm-overrides/*.yaml, especially the named charm files. Done means invalid standalone pairings are rejected, the DSL exposes the mandatory cross-model constraint, affected overrides are updated, and the Test Observer attachment rule is defined.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- testing, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100