This attempts to document the article lifecycle. arts[] is trashed and rebuilt every time a group is entered. This is handled entirely by index_group() setup_hard_base() creates an array of 'valid' article numbers in base[] read_overview() populates arts[] from overview data (cached or XOVER) Articles are initialised with set_article() Key initial default values are: art->thread = ART_EXPIRED art->status = ART_UNREAD read_art_headers() then plugs in any gaps due to new articles not yet in the overview (or reads all the headers if there are no overviews). All articles that are verified as already present (ie loaded by read_overview()) or are newly added will have art->thread set to ART_UNTHREADED valid_artnum() is used to check if base[n] maps to any known arts[].artnum [ After this base[] is reused as the thread base pointer array, which involves a change of type from long to int. This is why the code is full of ugly (int) base[] casts ] parse_unread_arts() uses the newsrc bitmask to explicitly set art->status to either ART_UNREAD or ART_READ Therefore anything not in the bitmap will default to ART_UNREAD Any articles that still have art->thread set to ART_EXPIRED will have art->status set to ART_READ write_overview() rewrites the cached overview data for any articles above the group low watermark where arts->thread != ART_EXPIRED build_references() doesn't affect any of this make_threads() in essence does: if (arts[i].thread >= 0) arts[i].thread = ART_UNTHREADED; to 'unthread' all the currently threaded & valid arts and calls find_base() find_base() will not thread articles with ->thread == ART_EXPIRED It makes no actual changes to ->status or ->thread