In a large heavy pot or Dutch oven, melt butter with olive oil over medium heat. Add onions and salt.
Cook slowly, stirring occasionally, for 35–45 minutes, until onions are deep golden brown and caramelized. (If they start browning too fast, lower the heat and add a splash of water to deglaze.)
Add garlic and diced ham; cook 1-2 minutes. Pour in juice and scrape up browned bits from the bottom. Simmer until mostly evaporated, about 2–3 minutes.
Add stock, thyme, bay leaf, pepper, and Worcestershire. Bring to a gentle simmer and cook 20–25 minutes, uncovered, for flavors to deepen. Taste and adjust seasoning. Remove bay leaf before serving.
While soup is simmering, preheat oven to 400°F (200°C).
Unfold the puff pastry onto a lightly floured surface. Cut into 8 equal rectangles (or larger rounds if you prefer a dramatic look).
Place on a parchment-lined baking sheet, brush with egg wash, and sprinkle lightly with flaky salt or Parmesan. Bake 12–15 minutes, or until golden and puffed. Set aside.
Once the soup and puff pastry is done, preheat the broiler to high and ladle hot soup into oven-safe bowls. Add a puff pastry to each bowl, letting them soak slightly. Top with a generous handful of the cheddar–Gruyère mixture.
Broil for 2–3 minutes, until the cheese is melted, bubbling, and golden brown.
Let cool a few minutes before serving.