The parts of a rule
FREQ is the only required part: DAILY, WEEKLY, MONTHLY or YEARLY. INTERVAL multiplies it, so FREQ=WEEKLY;INTERVAL=2 is fortnightly. COUNT ends the series after a number of occurrences and UNTIL ends it on a date; you use one or the other, never both.
Then the BY parts, which select within each period. BYDAY takes weekdays, optionally with an ordinal — 2TU is the second Tuesday, -1FR the last Friday. BYMONTHDAY takes days of the month and accepts negatives, so -1 is the last day. BYMONTH restricts to particular months. BYSETPOS picks positions out of whatever the other rules produced in each period — which is how “the last weekday of the month” is expressed, as in the rule above.
WKST declares which day the week starts on. It looks decorative and it is not: for interval rules that straddle a week boundary it changes which dates you get, and it is a real source of two calendars disagreeing about the same rule.
What plugins usually implement
Frequency and interval, and then it varies. The common stopping point is exactly there — daily, weekly, monthly, yearly, times an interval — with no ordinal weekday handling at all. Give such a plugin BYDAY=2TU and it produces “monthly on the same date”, with no error.
That silence is the real problem. A plugin that said “I cannot expand this rule” would be fine; you would pick another one. A plugin that produces confident wrong dates costs somebody a wasted evening.
Exclusions and additions
EXDATE removes specific dates from a series; RDATE adds one-off dates to it. Both live alongside the rule rather than in it. EXDATE is very commonly parsed and then never applied — the exclusion is stored and ignored at expansion time, so cancelled dates keep appearing.
Remember the ordering: COUNT applies to what the rule generates, and exclusions are subtracted afterwards. Ten occurrences with one excluded is nine, not ten.
The parts almost nobody needs
BYYEARDAY, BYWEEKNO, and the sub-daily frequencies exist in the specification and essentially never appear in real calendar feeds. A plugin that does not implement them is not deficient. A plugin that does not tell you it has not implemented something is.
The expander above reports anything it will not expand, rather than quietly returning a shorter or wrong list. That is the behaviour to demand — from us and from anyone else.