code: def _process_cascaded_category_contents(records):
      
      category_prot_records = {rec.category_id for rec in records if rec.type == EntryType.category
                               and rec.change == ChangeType.protection_changed}
      category_move_records = {rec.category_id for rec in records if rec.type == EntryType.category
                               and rec.change == ChangeType.moved}
  
      changed_events = set()
  
      category_prot_records -= category_move_records  # A move already implies sending the whole record
  
      # Protection changes are handled differently, as there may not be the need to re-generate the record
      if category_prot_records:
          for categ in Category.find(Category.id.in_(category_prot_records)):
              cte = categ.get_protection_parent_cte()
              # Update only children that inherit
              inheriting_categ_children = (Event.query
                                           .join(cte, db.and_((Event.category_id == cte.c.id),
                                                              (cte.c.protection_parent == categ.id))))
              inheriting_direct_children = Event.find((Event.category_id == categ.id) & Event.is_inheriting)
  
              changed_events.update(itertools.chain(inheriting_direct_children, inheriting_categ_children))
  
      # Add move operations and explicitly-passed event records
      if category_move_records:
          changed_events.update(Event.find(Event.category_chain_overlaps(category_move_records)))
  
      for elem in _process_cascaded_event_contents(records, additional_events=changed_events):
          yield elem
docs: Travel from categories to subcontributions, flattening the whole event structure.
  
      Yields everything that it finds (except for elements whose protection has changed
      but are not inheriting their protection settings from anywhere).
  
      :param records: queue records to process